├── .github ├── ISSUE_TEMPLATE.md ├── main.workflow └── workflows │ ├── nodejs.yml │ └── release.yml ├── .gitignore ├── .huskyrc ├── .nvmrc ├── .prettierIgnore ├── .prettierrc ├── Alerts.vue ├── BaseLayout.vue ├── CHANGELOG.md ├── LICENSE ├── __tests__ └── validation │ └── rules │ ├── accepted.test.js │ ├── after.test.js │ ├── after_or_equal.test.js │ ├── alpha.test.js │ ├── alpha_num.test.js │ ├── array.test.js │ ├── before.test.js │ ├── before_or_equal.test.js │ ├── between.js │ ├── boolean.test.js │ ├── confirmed.test.js │ ├── date.test.js │ ├── different.test.js │ ├── email.test.js │ ├── image.test.js │ ├── integer.test.js │ ├── max.test.js │ ├── mimetypes.test.js │ ├── min.test.js │ ├── nullable.test.js │ ├── numeric.test.js │ ├── regex.test.js │ ├── required.test.js │ ├── required_if.test.js │ ├── required_unless.test.js │ ├── required_with.test.js │ ├── required_with_all.test.js │ ├── required_without.test.js │ ├── required_without_all.test.js │ ├── same.test.js │ ├── size.test.js │ ├── string.test.js │ └── url.test.js ├── babel.config.js ├── commitlint.config.js ├── components └── Alert.vue ├── jest.config.js ├── package-lock.json ├── package.json ├── readme.md ├── release.config.js ├── src ├── config │ ├── ConfigInterface.ts │ ├── ConfigService.ts │ └── ConfigServiceProvider.ts ├── cookies │ ├── CookieInterface.ts │ ├── CookieService.ts │ └── CookieServiceProvider.ts ├── foundation │ ├── Application.ts │ ├── ApplicationInterface.ts │ └── ContainerMixin.ts ├── globals.ts ├── http │ ├── AxiosHttpService.ts │ ├── HttpServiceInterface.ts │ ├── HttpServiceProvider.ts │ ├── config.ts │ └── interfaces │ │ ├── HttpErrorInterface.ts │ │ ├── HttpMiddlewareInterface.ts │ │ ├── HttpRequestConfigInterface.ts │ │ └── HttpResponseInterface.ts ├── index.ts ├── plugins │ ├── alerts │ │ ├── AlertService.ts │ │ ├── AlertServiceInterface.ts │ │ ├── AlertServiceProvider.ts │ │ ├── Alerts.ts │ │ ├── alert-store │ │ │ ├── AlertStore.ts │ │ │ ├── actions.ts │ │ │ ├── mutations.ts │ │ │ ├── state.ts │ │ │ └── stateInterface.ts │ │ ├── config.ts │ │ └── models │ │ │ └── AlertModel.ts │ ├── autoRegisterComponents │ │ └── AutoRegisterComponentServiceProvider.ts │ ├── autoRegisterDirectives │ │ └── AutoRegisterDirectiveServiceProvider.ts │ ├── autoRegisterFilters │ │ └── AutoRegisterFilterServiceProvider.ts │ ├── autoRegisterLayouts │ │ └── AutoRegisterLayoutServiceProvider.ts │ ├── autoRegisterMixins │ │ └── AutoRegisterMixinServiceProvider.ts │ └── forms │ │ ├── Form.ts │ │ ├── FormServiceProvider.ts │ │ └── FormsPlugin.ts ├── routing │ ├── Route.ts │ ├── RouteMiddlewareInterface.ts │ ├── RouterInterface.ts │ ├── RoutesInterface.ts │ ├── RoutingServiceProvider.ts │ ├── VueRouterService.ts │ └── config.ts ├── state │ ├── StateServiceInterface.ts │ ├── StateServiceProvider.ts │ ├── StoreModule.ts │ └── VuexService.ts ├── storage │ ├── StorageService.ts │ ├── StorageServiceInterface.ts │ └── StorageServiceProvider.ts ├── support │ ├── Model.ts │ ├── ServiceProvider.ts │ └── ServiceProviderInterface.ts ├── utilities │ ├── camelize.ts │ ├── clone.ts │ ├── dashify.ts │ ├── filterEmpty.ts │ ├── getByDot.ts │ ├── index.ts │ ├── isEmpty.ts │ ├── setByDot.ts │ └── uncamelize.ts ├── validation │ ├── Validation.ts │ ├── ValidationServiceInterface.ts │ ├── ValidationServiceProvider.ts │ ├── Validator.ts │ ├── VarieValidationService.ts │ ├── config.ts │ ├── directive │ │ └── Validate.ts │ └── rules │ │ ├── accepted.ts │ │ ├── after.ts │ │ ├── after_or_equal.ts │ │ ├── alpha.ts │ │ ├── alpha_num.ts │ │ ├── array.ts │ │ ├── before.ts │ │ ├── before_or_equal.ts │ │ ├── between.ts │ │ ├── boolean.ts │ │ ├── confirmed.ts │ │ ├── date.ts │ │ ├── different.ts │ │ ├── email.ts │ │ ├── image.ts │ │ ├── index.ts │ │ ├── integer.ts │ │ ├── max.ts │ │ ├── mimetypes.ts │ │ ├── min.ts │ │ ├── nullable.ts │ │ ├── numeric.ts │ │ ├── regex.ts │ │ ├── required.ts │ │ ├── required_if.ts │ │ ├── required_unless.ts │ │ ├── required_with.ts │ │ ├── required_with_all.ts │ │ ├── required_without.ts │ │ ├── required_without_all.ts │ │ ├── same.ts │ │ ├── size.ts │ │ ├── string.ts │ │ └── url.ts └── vue-component.d.ts ├── stubs ├── appMiddleware.ts ├── component.vue ├── directive.ts ├── filter.ts ├── mixin.ts ├── model.ts ├── provider.ts ├── routeMiddleware.ts ├── rule.ts ├── service.ts ├── store │ ├── actions.ts │ ├── getters.ts │ ├── index.ts │ ├── mutations.ts │ ├── state.ts │ └── stateInterface.ts └── validator.ts └── tsconfig.json /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - Varie Version: #.#.# 2 | - Node Version: #.#.# 3 | 4 | ### Description: 5 | 6 | ### Steps To Reproduce: 7 | -------------------------------------------------------------------------------- /.github/main.workflow: -------------------------------------------------------------------------------- 1 | workflow "Build, Test, and Publish" { 2 | resolves = ["Release"] 3 | on = "release" 4 | } 5 | 6 | # Filter for master branch 7 | action "Is Master" { 8 | uses = "actions/bin/filter@master" 9 | args = "branch master" 10 | } 11 | 12 | action "Install Dependencies" { 13 | needs = "Is Master" 14 | uses = "actions/npm@master" 15 | args = "ci" 16 | } 17 | 18 | action "Install Peer Dependencies" { 19 | needs = "Install Dependencies" 20 | uses = "actions/npm@master" 21 | args = "run installPeers" 22 | } 23 | 24 | action "Test" { 25 | needs = "Install Peer Dependencies" 26 | uses = "actions/npm@master" 27 | args = "test" 28 | } 29 | 30 | action "Build" { 31 | needs = "Test" 32 | uses = "actions/npm@master" 33 | args = "build" 34 | } 35 | 36 | action "Release" { 37 | needs = "Build" 38 | uses = "actions/npm@master" 39 | args = "run release" 40 | secrets = ["GITHUB_TOKEN", "NPM_TOKEN"] 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" # matches every branch 7 | - "*/*" # matches every branch containing a single '/' 8 | - "!master" # excludes master 9 | 10 | jobs: 11 | test: 12 | name: Test on node ${{ matrix.node_version }} and ${{ matrix.os }} 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | node_version: [10.x, 12.x] 17 | os: [ubuntu-latest, macOS-latest] 18 | 19 | steps: 20 | - uses: actions/checkout@v1 21 | - name: Use Node.js ${{ matrix.node_version }} 22 | uses: actions/setup-node@v1 23 | with: 24 | version: ${{ matrix.node_version }} 25 | 26 | - name: npm install, build and test 27 | run: | 28 | npm ci 29 | npm run installPeers 30 | npm run build 31 | npm test 32 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Semantic Release 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [12.x] 19 | 20 | steps: 21 | - uses: actions/checkout@v1 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - name: npm install, build, test, and release 27 | run: | 28 | npm ci 29 | npm run installPeers 30 | npm run build 31 | npm test 32 | npm run release 33 | env: 34 | CI: true 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log* 3 | lib 4 | -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | # ~/.huskyrc 2 | export NVM_DIR="$HOME/.nvm" 3 | [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 12.13.1 2 | 3 | -------------------------------------------------------------------------------- /.prettierIgnore: -------------------------------------------------------------------------------- 1 | lib/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi" : true, 6 | "singleQuote": false, 7 | "trailingComma": "all", 8 | "bracketSpacing" : true, 9 | "jsxBracketSameLine": false, 10 | "arrowParens": "always", 11 | "rangeStart" : 0, 12 | "requirePragma" : false, 13 | "insertPragma" : false, 14 | "proseWrap" : "preserve" 15 | } -------------------------------------------------------------------------------- /Alerts.vue: -------------------------------------------------------------------------------- 1 | 79 | 80 | 87 | 88 | 102 | -------------------------------------------------------------------------------- /BaseLayout.vue: -------------------------------------------------------------------------------- 1 | 4 | 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See 4 | [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.0.1](https://github.com/variejs/varie-framework/compare/v1.0.0...v1.0.1) (2020-01-21) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * 🐛 build to es5 ([bad0129](https://github.com/variejs/varie-framework/commit/bad01299e8fabe1d54e31439e12e31d4cad4918b)) 12 | 13 | # 1.0.0 (2019-12-01) 14 | 15 | 16 | ### Bug Fixes 17 | 18 | * 🐛 casing for application ([#91](https://github.com/variejs/varie-framework/issues/91)) ([79d334d](https://github.com/variejs/varie-framework/commit/79d334da03658b7ae576cf0e42238d96e3a3c6a3)) 19 | * 🐛 props should be defaulted to true instead of an object ([557bcd9](https://github.com/variejs/varie-framework/commit/557bcd9093bf5f6447c90087ddfac49df3b41f93)) 20 | 21 | 22 | ### BREAKING CHANGES 23 | 24 | * route props are now defaulted to true 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 variejs 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 | -------------------------------------------------------------------------------- /__tests__/validation/rules/accepted.test.js: -------------------------------------------------------------------------------- 1 | import accepted from "../../../src/validation/rules/accepted"; 2 | 3 | test("test accepted rule", () => { 4 | expect(accepted.passes(1)).toBe(true); 5 | expect(accepted.passes(true)).toBe(true); 6 | expect(accepted.passes("yes")).toBe(true); 7 | 8 | expect(accepted.passes("1")).toBe(false); 9 | expect(accepted.passes("true")).toBe(false); 10 | }); 11 | -------------------------------------------------------------------------------- /__tests__/validation/rules/after.test.js: -------------------------------------------------------------------------------- 1 | import after from "../../../src/validation/rules/after"; 2 | 3 | test("test after rule", () => { 4 | expect(after.passes("1999-11-22", ["1990-11-22"])).toBe(true); 5 | expect(after.passes("1989-11-22", ["1990-11-22"])).toBe(false); 6 | expect(after.passes("1989-13-11", ["1990-11-22"])).toBe(false); 7 | expect(after.passes("89-13-11", ["1990-11-22"])).toBe(false); 8 | expect(after.passes("11", ["1990-11-22"])).toBe(false); 9 | }); 10 | -------------------------------------------------------------------------------- /__tests__/validation/rules/after_or_equal.test.js: -------------------------------------------------------------------------------- 1 | import after_or_equal from "../../../src/validation/rules/after_or_equal"; 2 | 3 | test("test after or equal rule", () => { 4 | expect(after_or_equal.passes("1999-11-23", ["1990-11-22"])).toBe(true); 5 | expect(after_or_equal.passes("1990-11-22", ["1990-11-22"])).toBe(true); 6 | expect(after_or_equal.passes("1990-11-21", ["1990-11-22"])).toBe(false); 7 | expect(after_or_equal.passes("1990-11-20", ["1990-11-22"])).toBe(false); 8 | }); 9 | -------------------------------------------------------------------------------- /__tests__/validation/rules/alpha.test.js: -------------------------------------------------------------------------------- 1 | import alpha from "../../../src/validation/rules/alpha"; 2 | 3 | test("test alpha rule", () => { 4 | let valid = ["abc", "ABC", "FoObar"]; 5 | 6 | let invalid = ["abc1", " foo ", "", "ÄBC", "FÜübar", "Jön", "Heiß", "123"]; 7 | 8 | valid.forEach((value) => { 9 | expect(alpha.passes(value)).toBe(true); 10 | }); 11 | 12 | invalid.forEach((value) => { 13 | expect(alpha.passes(value)).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /__tests__/validation/rules/alpha_num.test.js: -------------------------------------------------------------------------------- 1 | import alpha_num from "../../../src/validation/rules/alpha_num"; 2 | 3 | test("test alpha num rule", () => { 4 | let valid = ["abc123", "ABC11", "123"]; 5 | 6 | let invalid = [" foo ", "", "ÄBC", "FÜübar", "Jön", "Heiß"]; 7 | 8 | valid.forEach((value) => { 9 | expect(alpha_num.passes(value)).toBe(true); 10 | }); 11 | 12 | invalid.forEach((value) => { 13 | expect(alpha_num.passes(value)).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /__tests__/validation/rules/array.test.js: -------------------------------------------------------------------------------- 1 | import array from "../../../src/validation/rules/array"; 2 | 3 | test("test array rule", () => { 4 | let valid = [[1, 2, 3]]; 5 | 6 | let invalid = [" foo ", {}]; 7 | 8 | valid.forEach((value) => { 9 | expect(array.passes(value)).toBe(true); 10 | }); 11 | 12 | invalid.forEach((value) => { 13 | expect(array.passes(value)).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /__tests__/validation/rules/before.test.js: -------------------------------------------------------------------------------- 1 | import before from "../../../src/validation/rules/before"; 2 | 3 | test("test before rule", () => { 4 | expect(before.passes("1999-11-22", ["1990-11-22"])).toBe(false); 5 | expect(before.passes("1989-11-22", ["1990-11-22"])).toBe(true); 6 | expect(before.passes("1989-13-11", ["1990-11-22"])).toBe(false); 7 | expect(before.passes("89-13-11", ["1990-11-22"])).toBe(false); 8 | expect(before.passes("11", ["1990-11-22"])).toBe(false); 9 | }); 10 | -------------------------------------------------------------------------------- /__tests__/validation/rules/before_or_equal.test.js: -------------------------------------------------------------------------------- 1 | import before_or_equal from "../../../src/validation/rules/before_or_equal"; 2 | 3 | test("test before or equal rule", () => { 4 | expect(before_or_equal.passes("1999-11-23", ["1990-11-22"])).toBe(false); 5 | expect(before_or_equal.passes("1990-11-22", ["1990-11-22"])).toBe(true); 6 | expect(before_or_equal.passes("1990-11-21", ["1990-11-22"])).toBe(true); 7 | expect(before_or_equal.passes("1990-11-20", ["1990-11-22"])).toBe(true); 8 | }); 9 | -------------------------------------------------------------------------------- /__tests__/validation/rules/between.js: -------------------------------------------------------------------------------- 1 | import between from "../../../src/validation/rules/between"; 2 | import min from "../../../src/validation/rules/min"; 3 | 4 | test("test between rule", () => { 5 | expect(min.passes("a", [3, 10])).toBe(false); 6 | expect(min.passes("asd", [3, 10])).toBe(true); 7 | expect(min.passes("abdadfaaa", [3, 10])).toBe(true); 8 | expect(min.passes("abdadfaa", [3, 10])).toBe(true); 9 | 10 | expect(between.passes(5, [1, 10])).toBe(true); 11 | expect(between.passes(123, [1, 10])).toBe(false); 12 | 13 | // act as a file 14 | expect( 15 | between.passes( 16 | { 17 | size: 3500000, // 3500 kb 18 | }, 19 | [2000, 4000], 20 | ), 21 | ).toBe(true); 22 | expect( 23 | between.passes( 24 | { 25 | size: 1500000, // 1500 kb 26 | }, 27 | [2000, 4000], 28 | ), 29 | ).toBe(false); 30 | }); 31 | -------------------------------------------------------------------------------- /__tests__/validation/rules/boolean.test.js: -------------------------------------------------------------------------------- 1 | import boolean from "../../../src/validation/rules/boolean"; 2 | 3 | test("test boolean rule", () => { 4 | let valid = [true, false, 0, 1]; 5 | 6 | let invalid = ["1", "0", 2, "abc"]; 7 | 8 | valid.forEach((value) => { 9 | expect(boolean.passes(value)).toBe(true); 10 | }); 11 | 12 | invalid.forEach((value) => { 13 | expect(boolean.passes(value)).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /__tests__/validation/rules/confirmed.test.js: -------------------------------------------------------------------------------- 1 | import confirmed from "../../../src/validation/rules/confirmed"; 2 | 3 | test("test confirmed rule", () => { 4 | expect( 5 | confirmed.passes( 6 | "abc", 7 | [], 8 | { 9 | password: "abc", 10 | password_confirmation: "abc", 11 | }, 12 | "password", 13 | ), 14 | ).toBe(true); 15 | 16 | expect( 17 | confirmed.passes( 18 | "abc", 19 | [], 20 | { 21 | password: "abc", 22 | password_confirmation: "abcd", 23 | }, 24 | "password", 25 | ), 26 | ).toBe(false); 27 | 28 | expect( 29 | confirmed.passes( 30 | "abc", 31 | [], 32 | { 33 | password: "abc", 34 | }, 35 | "password", 36 | ), 37 | ).toBe(false); 38 | }); 39 | -------------------------------------------------------------------------------- /__tests__/validation/rules/date.test.js: -------------------------------------------------------------------------------- 1 | import date from "../../../src/validation/rules/date"; 2 | 3 | test("test date rule", () => { 4 | expect(date.passes(new Date())).toBe(true); 5 | expect(date.passes("1999-11-22")).toBe(true); 6 | expect(date.passes("89-13-11")).toBe(false); 7 | expect(date.passes("11")).toBe(false); 8 | }); 9 | -------------------------------------------------------------------------------- /__tests__/validation/rules/different.test.js: -------------------------------------------------------------------------------- 1 | import different from "../../../src/validation/rules/different"; 2 | 3 | test("test different rule", () => { 4 | expect( 5 | different.passes("abcd", ["name"], { 6 | name: "abc", 7 | }), 8 | ).toBe(true); 9 | expect( 10 | different.passes("abc", ["name"], { 11 | name: "abc", 12 | }), 13 | ).toBe(false); 14 | }); 15 | -------------------------------------------------------------------------------- /__tests__/validation/rules/email.test.js: -------------------------------------------------------------------------------- 1 | import email from "../../../src/validation/rules/email"; 2 | 3 | function repeat(str, count) { 4 | let result = ""; 5 | for (; count; count--) { 6 | result += str; 7 | } 8 | return result; 9 | } 10 | 11 | test("test email rule", () => { 12 | let valid = [ 13 | "foo@bar.com", 14 | "x@x.au", 15 | "foo@bar.com.au", 16 | "foo+bar@bar.com", 17 | "hans.m端ller@test.com", 18 | "hans@m端ller.com", 19 | "test|123@m端ller.com", 20 | "test123+ext@gmail.com", 21 | "some.name.midd.leNa.me+extension@GoogleMail.com", 22 | '"foobar"@example.com', 23 | '" foo m端ller "@example.com', 24 | '"foo\\@bar"@example.com', 25 | `${repeat("a", 64)}@${repeat("a", 63)}.com`, 26 | `${repeat("a", 64)}@${repeat("a", 63)}.com`, 27 | `${repeat("a", 31)}@gmail.com`, 28 | "test@gmail.com", 29 | "test.1@gmail.com", 30 | ]; 31 | 32 | let invalid = [ 33 | "invalidemail@", 34 | "invalid.com", 35 | "@invalid.com", 36 | "foo@bar.com.", 37 | "somename@gmail.com", 38 | "foo@bar.co.uk.", 39 | "z@co.c", 40 | "gmailgmailgmailgmailgmail@gmail.com", 41 | `${repeat("a", 64)}@${repeat("a", 251)}.com`, 42 | `${repeat("a", 65)}@${repeat("a", 250)}.com`, 43 | `${repeat("a", 64)}@${repeat("a", 64)}.com`, 44 | `${repeat("a", 64)}@${repeat("a", 63)}.${repeat("a", 63)}.${repeat( 45 | "a", 46 | 63, 47 | )}.${repeat("a", 58)}.com`, 48 | "test1@invalid.co m", 49 | "test2@invalid.co m", 50 | "test3@invalid.co m", 51 | "test4@invalid.co m", 52 | "test5@invalid.co m", 53 | "test6@invalid.co m", 54 | "test7@invalid.co m", 55 | "test8@invalid.co m", 56 | "test9@invalid.co m", 57 | "test10@invalid.co m", 58 | "test11@invalid.co m", 59 | "test12@invalid.co m", 60 | "test13@invalid.co m", 61 | "multiple..dots@stillinvalid.com", 62 | "test123+invalid! sub_address@gmail.com", 63 | "gmail...ignores...dots...@gmail.com", 64 | "ends.with.dot.@gmail.com", 65 | "multiple..dots@gmail.com", 66 | 'wrong()[]",:;<>@@gmail.com', 67 | '"wrong()[]",:;<>@@gmail.com', 68 | ]; 69 | 70 | valid.forEach((value) => { 71 | expect(email.passes(value)).toBe(true); 72 | }); 73 | 74 | invalid.forEach((value) => { 75 | expect(email.passes(value)).toBe(false); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /__tests__/validation/rules/image.test.js: -------------------------------------------------------------------------------- 1 | import image from "../../../src/validation/rules/image"; 2 | 3 | test("test image rule", () => { 4 | let valid = ["jpg", "svg", "jpeg", "png", "bmp", "gif"]; 5 | 6 | let invalid = ["blah", "mp4", "pdf"]; 7 | 8 | valid.forEach((value) => { 9 | expect( 10 | image.passes({ 11 | name: `some_name.${value}`, 12 | }), 13 | ).toBe(true); 14 | }); 15 | 16 | valid.forEach((value) => { 17 | expect( 18 | image.passes({ 19 | type: `${value}`, 20 | }), 21 | ).toBe(true); 22 | }); 23 | 24 | invalid.forEach((value) => { 25 | expect( 26 | image.passes({ 27 | name: `some_name.${value}`, 28 | }), 29 | ).toBe(false); 30 | }); 31 | 32 | // invalid.forEach(value => { 33 | // expect( 34 | // image.passes({ 35 | // type: `${value}` 36 | // }) 37 | // ).toBe(false); 38 | // }); 39 | }); 40 | -------------------------------------------------------------------------------- /__tests__/validation/rules/integer.test.js: -------------------------------------------------------------------------------- 1 | import integer from "../../../src/validation/rules/integer"; 2 | 3 | test("test integer rule", () => { 4 | let valid = [1, 1231, 123123123, 1231232131]; 5 | 6 | let invalid = [1.1, "1.1", "12", 12313.14]; 7 | 8 | valid.forEach((value) => { 9 | expect(integer.passes(value)).toBe(true); 10 | }); 11 | 12 | invalid.forEach((value) => { 13 | expect(integer.passes(value)).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /__tests__/validation/rules/max.test.js: -------------------------------------------------------------------------------- 1 | import max from "../../../src/validation/rules/max"; 2 | 3 | test("test max rule", () => { 4 | expect(max.passes("asd", [3])).toBe(true); 5 | expect(max.passes("123", [3])).toBe(true); 6 | expect(max.passes("1234", [3])).toBe(false); 7 | 8 | expect(max.passes(9, [10])).toBe(true); 9 | expect(max.passes(10, [10])).toBe(true); 10 | expect(max.passes(123, [10])).toBe(false); 11 | 12 | // act as a file 13 | expect( 14 | max.passes( 15 | { 16 | size: 3500000, // 3500 kb 17 | }, 18 | [4000], 19 | ), 20 | ).toBe(true); 21 | 22 | expect( 23 | max.passes( 24 | { 25 | size: 4096000, // 4000 kb 26 | }, 27 | [4000], 28 | ), 29 | ).toBe(true); 30 | 31 | expect( 32 | max.passes( 33 | { 34 | size: 5500000, // 5500 kb 35 | }, 36 | [4000], 37 | ), 38 | ).toBe(false); 39 | }); 40 | -------------------------------------------------------------------------------- /__tests__/validation/rules/mimetypes.test.js: -------------------------------------------------------------------------------- 1 | import mimetypes from "../../../src/validation/rules/mimetypes"; 2 | 3 | class MockFile { 4 | constructor(type) { 5 | this.type = type; 6 | } 7 | } 8 | 9 | test("test mimetype rule", () => { 10 | let valid = ["jpg", "svg", "jpeg", "png", "bmp", "gif"]; 11 | 12 | let invalid = ["blah", "mp4", "pdf"]; 13 | 14 | valid.forEach((value) => { 15 | expect(mimetypes.passes(new MockFile(value), valid)).toBe(true); 16 | }); 17 | 18 | invalid.forEach((value) => { 19 | expect(mimetypes.passes(new MockFile(value), valid)).toBe(false); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /__tests__/validation/rules/min.test.js: -------------------------------------------------------------------------------- 1 | import min from "../../../src/validation/rules/min"; 2 | import max from "../../../src/validation/rules/max"; 3 | 4 | test("test min rule", () => { 5 | expect(min.passes("asd", [3])).toBe(true); 6 | expect(min.passes("12", [3])).toBe(false); 7 | expect(min.passes("1234", [3])).toBe(true); 8 | 9 | expect(min.passes(9, [10])).toBe(false); 10 | expect(min.passes(10, [10])).toBe(true); 11 | expect(min.passes(123, [10])).toBe(true); 12 | 13 | expect( 14 | min.passes( 15 | { 16 | size: 3500000, // 3500 kb 17 | }, 18 | [4000], 19 | ), 20 | ).toBe(false); 21 | 22 | expect( 23 | min.passes( 24 | { 25 | size: 4096000, // 4000 kb 26 | }, 27 | [4000], 28 | ), 29 | ).toBe(true); 30 | 31 | expect( 32 | min.passes( 33 | { 34 | size: 5500000, // 5500 kb 35 | }, 36 | [4000], 37 | ), 38 | ).toBe(true); 39 | }); 40 | -------------------------------------------------------------------------------- /__tests__/validation/rules/nullable.test.js: -------------------------------------------------------------------------------- 1 | import nullable from "../../../src/validation/rules/nullable"; 2 | 3 | test("test nullable rule", () => { 4 | let valid = ["", " ", {}, [], undefined, null]; 5 | 6 | let invalid = [" foo ", { test: true }, [1]]; 7 | 8 | valid.forEach((value) => { 9 | expect(nullable.passes(value)).toBe(true); 10 | }); 11 | 12 | invalid.forEach((value) => { 13 | expect(nullable.passes(value)).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /__tests__/validation/rules/numeric.test.js: -------------------------------------------------------------------------------- 1 | import numeric from "../../../src/validation/rules/numeric"; 2 | 3 | test("test numeric rule", () => { 4 | let valid = [1, 2.15, 123]; 5 | 6 | let invalid = [" foo "]; 7 | 8 | valid.forEach((value) => { 9 | expect(numeric.passes(value)).toBe(true); 10 | }); 11 | 12 | invalid.forEach((value) => { 13 | expect(numeric.passes(value)).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /__tests__/validation/rules/regex.test.js: -------------------------------------------------------------------------------- 1 | import regex from "../../../src/validation/rules/regex"; 2 | 3 | test("test regex rule", () => { 4 | let valid = [/^[A-Za-z0-9]+$/, "^[A-Za-z0-9]+$"]; 5 | 6 | let invalid = [/abc/, "abc"]; 7 | 8 | valid.forEach((value) => { 9 | expect(regex.passes("ABC123", [value])).toBe(true); 10 | }); 11 | 12 | valid.forEach((value) => { 13 | expect(regex.passes("...FAIL...", [value])).toBe(false); 14 | }); 15 | 16 | invalid.forEach((value) => { 17 | expect(regex.passes("...FAIL...", [value])).toBe(false); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /__tests__/validation/rules/required.test.js: -------------------------------------------------------------------------------- 1 | import required from "../../../src/validation/rules/required"; 2 | 3 | test("test required rule", () => { 4 | expect(required.passes("abc")).toBe(true); 5 | expect(required.passes({ test: true })).toBe(true); 6 | expect(required.passes([1])).toBe(true); 7 | 8 | expect(required.passes("")).toBe(false); 9 | expect(required.passes({})).toBe(false); 10 | expect(required.passes([])).toBe(false); 11 | expect(required.passes(null)).toBe(false); 12 | expect(required.passes(undefined)).toBe(false); 13 | }); 14 | -------------------------------------------------------------------------------- /__tests__/validation/rules/required_if.test.js: -------------------------------------------------------------------------------- 1 | import required_if from "../../../src/validation/rules/required_if"; 2 | 3 | test("test required if rule", () => { 4 | expect( 5 | required_if.passes("asdfadsf", ["name", "abc"], { 6 | name: "abc", 7 | }), 8 | ).toBe(true); 9 | 10 | expect( 11 | required_if.passes("", ["name", "abc"], { 12 | name: "abc", 13 | }), 14 | ).toBe(false); 15 | 16 | expect( 17 | required_if.passes("", ["name"], { 18 | name: "abc", 19 | }), 20 | ).toBe(false); 21 | 22 | expect( 23 | required_if.passes("", ["name"], { 24 | name: null, 25 | }), 26 | ).toBe(true); 27 | }); 28 | -------------------------------------------------------------------------------- /__tests__/validation/rules/required_unless.test.js: -------------------------------------------------------------------------------- 1 | import required_unless from "../../../src/validation/rules/required_unless"; 2 | 3 | test("test required unless rule", () => { 4 | expect( 5 | required_unless.passes("abc", ["name", "abc"], { 6 | name: "abc", 7 | }), 8 | ).toBe(true); 9 | 10 | expect( 11 | required_unless.passes("", ["name", "abc"], { 12 | name: "abc", 13 | }), 14 | ).toBe(false); 15 | 16 | expect( 17 | required_unless.passes("", ["name"], { 18 | name: "abc", 19 | }), 20 | ).toBe(false); 21 | 22 | expect( 23 | required_unless.passes("", ["name"], { 24 | name: "", 25 | }), 26 | ).toBe(true); 27 | }); 28 | -------------------------------------------------------------------------------- /__tests__/validation/rules/required_with.test.js: -------------------------------------------------------------------------------- 1 | import required_with from "../../../src/validation/rules/required_with"; 2 | 3 | test("test required with rule", () => { 4 | expect( 5 | required_with.passes("abc", ["name"], { 6 | name: "abc", 7 | }), 8 | ).toBe(true); 9 | 10 | expect( 11 | required_with.passes("", ["name"], { 12 | name: "abc", 13 | }), 14 | ).toBe(false); 15 | 16 | expect( 17 | required_with.passes("", ["name", "sir_name"], { 18 | name: "", 19 | sir_name: "test", 20 | }), 21 | ).toBe(false); 22 | }); 23 | -------------------------------------------------------------------------------- /__tests__/validation/rules/required_with_all.test.js: -------------------------------------------------------------------------------- 1 | import required_with_all from "../../../src/validation/rules/required_with_all"; 2 | 3 | test("test required with all rule", () => { 4 | expect( 5 | required_with_all.passes("abc", ["name"], { 6 | name: "abc", 7 | }), 8 | ).toBe(true); 9 | 10 | expect( 11 | required_with_all.passes("", ["name"], { 12 | name: "abc", 13 | }), 14 | ).toBe(false); 15 | 16 | expect( 17 | required_with_all.passes("", ["name", "sir_name"], { 18 | name: "", 19 | sir_name: "test", 20 | }), 21 | ).toBe(true); 22 | 23 | expect( 24 | required_with_all.passes("", ["name", "sir_name"], { 25 | name: "asdfadsf", 26 | sir_name: "test", 27 | }), 28 | ).toBe(false); 29 | }); 30 | -------------------------------------------------------------------------------- /__tests__/validation/rules/required_without.test.js: -------------------------------------------------------------------------------- 1 | import required_without from "../../../src/validation/rules/required_without"; 2 | 3 | test("test required without rule", () => { 4 | expect( 5 | required_without.passes("abc", ["name"], { 6 | name: "abc", 7 | }), 8 | ).toBe(true); 9 | 10 | expect( 11 | required_without.passes("", ["name"], { 12 | name: "", 13 | }), 14 | ).toBe(false); 15 | 16 | expect( 17 | required_without.passes("", ["name"], { 18 | name: "abc", 19 | }), 20 | ).toBe(true); 21 | 22 | expect( 23 | required_without.passes("", ["name", "sir_name"], { 24 | name: "", 25 | sir_name: "test", 26 | }), 27 | ).toBe(false); 28 | }); 29 | -------------------------------------------------------------------------------- /__tests__/validation/rules/required_without_all.test.js: -------------------------------------------------------------------------------- 1 | import required_without_all from "../../../src/validation/rules/required_without_all"; 2 | 3 | test("test without all rule", () => { 4 | expect( 5 | required_without_all.passes("abc", ["name"], { 6 | name: "abc", 7 | }), 8 | ).toBe(true); 9 | 10 | expect( 11 | required_without_all.passes("", ["name"], { 12 | name: "abc", 13 | }), 14 | ).toBe(true); 15 | 16 | expect( 17 | required_without_all.passes("", ["name", "sir_name"], { 18 | name: "", 19 | sir_name: "test", 20 | }), 21 | ).toBe(true); 22 | 23 | expect( 24 | required_without_all.passes("", ["name", "sir_name"], { 25 | name: "asdfasdf", 26 | sir_name: "test", 27 | }), 28 | ).toBe(true); 29 | 30 | expect( 31 | required_without_all.passes("", ["name", "sir_name"], { 32 | name: "", 33 | sir_name: "", 34 | }), 35 | ).toBe(false); 36 | }); 37 | -------------------------------------------------------------------------------- /__tests__/validation/rules/same.test.js: -------------------------------------------------------------------------------- 1 | import same from "../../../src/validation/rules/same"; 2 | 3 | test("test same rule", () => { 4 | let valid = ["abc"]; 5 | 6 | let invalid = [" foo ", {}]; 7 | 8 | valid.forEach((value) => { 9 | expect( 10 | same.passes(value, ["name"], { 11 | name: "abc", 12 | }), 13 | ).toBe(true); 14 | }); 15 | 16 | invalid.forEach((value) => { 17 | expect( 18 | same.passes(value, ["name"], { 19 | name: "abc", 20 | }), 21 | ).toBe(false); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /__tests__/validation/rules/size.test.js: -------------------------------------------------------------------------------- 1 | import size from "../../../src/validation/rules/size"; 2 | 3 | test("test size rule", () => { 4 | expect(size.passes(9, [10])).toBe(false); 5 | expect(size.passes(10, [10])).toBe(true); 6 | expect(size.passes(123, [10])).toBe(false); 7 | 8 | // act as a file 9 | expect( 10 | size.passes( 11 | { 12 | size: 3500000, // 3500 kb 13 | }, 14 | [4000], 15 | ), 16 | ).toBe(false); 17 | 18 | expect( 19 | size.passes( 20 | { 21 | size: 4096000, // 4000 kb 22 | }, 23 | [4000], 24 | ), 25 | ).toBe(true); 26 | 27 | expect( 28 | size.passes( 29 | { 30 | size: 5500000, // 5500 kb 31 | }, 32 | [4000], 33 | ), 34 | ).toBe(false); 35 | }); 36 | -------------------------------------------------------------------------------- /__tests__/validation/rules/string.test.js: -------------------------------------------------------------------------------- 1 | import string from "../../../src/validation/rules/string"; 2 | 3 | test("test string rule", () => { 4 | expect(string.passes("abc")).toBe(true); 5 | expect(string.passes(123)).toBe(false); 6 | expect(string.passes("123")).toBe(true); 7 | }); 8 | -------------------------------------------------------------------------------- /__tests__/validation/rules/url.test.js: -------------------------------------------------------------------------------- 1 | import url from "../../../src/validation/rules/url"; 2 | 3 | test("test url rule", () => { 4 | let valid = [ 5 | "foobar.com", 6 | "www.foobar.com", 7 | "foobar.com/", 8 | "valid.au", 9 | "http://www.foobar.com/", 10 | "HTTP://WWW.FOOBAR.COM/", 11 | "https://www.foobar.com/", 12 | "HTTPS://WWW.FOOBAR.COM/", 13 | "http://www.foobar.com:23/", 14 | "http://www.foobar.com:65535/", 15 | "http://www.foobar.com:5/", 16 | "https://www.foobar.com/", 17 | "ftp://www.foobar.com/", 18 | "http://www.foobar.com/~foobar", 19 | "http://user:pass@www.foobar.com/", 20 | "http://user:@www.foobar.com/", 21 | "http://127.0.0.1/", 22 | "http://10.0.0.0/", 23 | "http://189.123.14.13/", 24 | "http://duckduckgo.com/?q=%2F", 25 | "http://foobar.com/t$-_.+!*'(),", 26 | "http://foobar.com/?foo=bar#baz=qux", 27 | "http://foobar.com?foo=bar", 28 | "http://foobar.com#baz=qux", 29 | "http://www.xn--froschgrn-x9a.net/", 30 | "http://xn--froschgrn-x9a.com/", 31 | "http://foo--bar.com", 32 | "http://høyfjellet.no", 33 | "http://xn--j1aac5a4g.xn--j1amh", 34 | "http://xn------eddceddeftq7bvv7c4ke4c.xn--p1ai", 35 | "http://кулік.укр", 36 | "test.com?ref=http://test2.com", 37 | "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html", 38 | "http://[1080:0:0:0:8:800:200C:417A]/index.html", 39 | "http://[3ffe:2a00:100:7031::1]", 40 | "http://[1080::8:800:200C:417A]/foo", 41 | "http://[::192.9.5.5]/ipng", 42 | "http://[::FFFF:129.144.52.38]:80/index.html", 43 | "http://[2010:836B:4179::836B:4179]", 44 | ]; 45 | 46 | let invalid = [ 47 | "http://localhost:3000/", 48 | "//foobar.com", 49 | "xyz://foobar.com", 50 | "invalid/", 51 | "invalid.x", 52 | "invalid.", 53 | ".com", 54 | "http://com/", 55 | "http://300.0.0.1/", 56 | "mailto:foo@bar.com", 57 | "rtmp://foobar.com", 58 | "http://www.xn--.com/", 59 | "http://xn--.com/", 60 | "http://www.foobar.com:0/", 61 | "http://www.foobar.com:70000/", 62 | "http://www.foobar.com:99999/", 63 | "http://www.-foobar.com/", 64 | "http://www.foobar-.com/", 65 | "http://foobar/# lol", 66 | "http://foobar/? lol", 67 | "http://foobar/ lol/", 68 | "http://lol @foobar.com/", 69 | "http://lol:lol @foobar.com/", 70 | "http://lol:lol:lol@foobar.com/", 71 | "http://lol: @foobar.com/", 72 | "http://www.foo_bar.com/", 73 | "http://www.foobar.com/\t", 74 | "http://\n@www.foobar.com/", 75 | "", 76 | `http://foobar.com/${new Array(2083).join("f")}`, 77 | "http://*.foo.com", 78 | "*.foo.com", 79 | "!.foo.com", 80 | "http://example.com.", 81 | "http://localhost:61500this is an invalid url!!!!", 82 | "////foobar.com", 83 | "http:////foobar.com", 84 | "https://example.com/foo//", 85 | ]; 86 | 87 | valid.forEach((value) => { 88 | expect(url.passes(value)).toBe(true); 89 | }); 90 | 91 | invalid.forEach((value) => { 92 | expect(url.passes(value)).toBe(false); 93 | }); 94 | }); 95 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | // babel.config.js 2 | module.exports = { 3 | presets: [ 4 | ["@babel/preset-env", { targets: { node: "current" } }], 5 | "@babel/preset-typescript", 6 | ], 7 | }; 8 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ["@commitlint/config-conventional"] }; 2 | -------------------------------------------------------------------------------- /components/Alert.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 33 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after `n` failures 9 | // bail: 0, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "/private/var/folders/r2/bykjzw3x2w9g5qsm5xvbb4400000gn/T/jest_dx", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | clearMocks: true, 19 | 20 | // Indicates whether the coverage information should be collected while executing the test 21 | // collectCoverage: false, 22 | 23 | // An array of glob patterns indicating a set of files for which coverage information should be collected 24 | // collectCoverageFrom: null, 25 | 26 | // The directory where Jest should output its coverage files 27 | // coverageDirectory: null, 28 | 29 | // An array of regexp pattern strings used to skip coverage collection 30 | // coveragePathIgnorePatterns: [ 31 | // "/node_modules/" 32 | // ], 33 | 34 | // A list of reporter names that Jest uses when writing coverage reports 35 | // coverageReporters: [ 36 | // "json", 37 | // "text", 38 | // "lcov", 39 | // "clover" 40 | // ], 41 | 42 | // An object that configures minimum threshold enforcement for coverage results 43 | // coverageThreshold: null, 44 | 45 | // A path to a custom dependency extractor 46 | // dependencyExtractor: null, 47 | 48 | // Make calling deprecated APIs throw helpful error messages 49 | // errorOnDeprecated: false, 50 | 51 | // Force coverage collection from ignored files using an array of glob patterns 52 | // forceCoverageMatch: [], 53 | 54 | // A path to a module which exports an async function that is triggered once before all test suites 55 | // globalSetup: null, 56 | 57 | // A path to a module which exports an async function that is triggered once after all test suites 58 | // globalTeardown: null, 59 | 60 | // A set of global variables that need to be available in all test environments 61 | // globals: {}, 62 | 63 | // An array of directory names to be searched recursively up from the requiring module's location 64 | // moduleDirectories: [ 65 | // "node_modules" 66 | // ], 67 | 68 | // An array of file extensions your modules use 69 | // moduleFileExtensions: [ 70 | // "js", 71 | // "json", 72 | // "jsx", 73 | // "ts", 74 | // "tsx", 75 | // "node" 76 | // ], 77 | 78 | // A map from regular expressions to module names that allow to stub out resources with a single module 79 | // moduleNameMapper: {}, 80 | 81 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 82 | // modulePathIgnorePatterns: [], 83 | 84 | // Activates notifications for test results 85 | // notify: false, 86 | 87 | // An enum that specifies notification mode. Requires { notify: true } 88 | // notifyMode: "failure-change", 89 | 90 | // A preset that is used as a base for Jest's configuration 91 | // preset: null, 92 | 93 | // Run tests from one or more projects 94 | // projects: null, 95 | 96 | // Use this configuration option to add custom reporters to Jest 97 | // reporters: undefined, 98 | 99 | // Automatically reset mock state between every test 100 | // resetMocks: false, 101 | 102 | // Reset the module registry before running each individual test 103 | // resetModules: false, 104 | 105 | // A path to a custom resolver 106 | // resolver: null, 107 | 108 | // Automatically restore mock state between every test 109 | // restoreMocks: false, 110 | 111 | // The root directory that Jest should scan for tests and modules within 112 | // rootDir: null, 113 | 114 | // A list of paths to directories that Jest should use to search for files in 115 | // roots: [ 116 | // "" 117 | // ], 118 | 119 | // Allows you to use a custom runner instead of Jest's default test runner 120 | // runner: "jest-runner", 121 | 122 | // The paths to modules that run some code to configure or set up the testing environment before each test 123 | // setupFiles: [], 124 | 125 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 126 | // setupFilesAfterEnv: [], 127 | 128 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 129 | // snapshotSerializers: [], 130 | 131 | // The test environment that will be used for testing 132 | testEnvironment: "node", 133 | 134 | // Options that will be passed to the testEnvironment 135 | // testEnvironmentOptions: {}, 136 | 137 | // Adds a location field to test results 138 | // testLocationInResults: false, 139 | 140 | // The glob patterns Jest uses to detect test files 141 | // testMatch: [ 142 | // "**/__tests__/**/*.[jt]s?(x)", 143 | // "**/?(*.)+(spec|test).[tj]s?(x)" 144 | // ], 145 | 146 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 147 | // testPathIgnorePatterns: [ 148 | // "/node_modules/" 149 | // ], 150 | 151 | // The regexp pattern or array of patterns that Jest uses to detect test files 152 | // testRegex: [], 153 | 154 | // This option allows the use of a custom results processor 155 | // testResultsProcessor: null, 156 | 157 | // This option allows use of a custom test runner 158 | // testRunner: "jasmine2", 159 | 160 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 161 | // testURL: "http://localhost", 162 | 163 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 164 | // timers: "real", 165 | 166 | // A map from regular expressions to paths to transformers 167 | // transform: null, 168 | 169 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 170 | // transformIgnorePatterns: [ 171 | // "/node_modules/" 172 | // ], 173 | 174 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 175 | // unmockedModulePathPatterns: undefined, 176 | 177 | // Indicates whether each individual test should be reported during the run 178 | // verbose: null, 179 | 180 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 181 | // watchPathIgnorePatterns: [], 182 | 183 | // Whether to use watchman for file crawling 184 | // watchman: true, 185 | }; 186 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "varie", 3 | "version": "1.0.1", 4 | "description": "VueJS Framework", 5 | "main": "./lib/index.js", 6 | "typings": "./lib/index", 7 | "types": "./lib/index", 8 | "repository": "git@github.com:variejs/varie-framework.git", 9 | "author": "Luke Policinski", 10 | "license": "MIT", 11 | "dependencies": { 12 | "axios": "^0.19.0", 13 | "camelcase": "^5.3.1", 14 | "clone-deep": "^4.0.1", 15 | "dashify": "^2.0.0", 16 | "inversify": "^5.0.1", 17 | "inversify-inject-decorators": "^3.1.0", 18 | "reflect-metadata": "^0.1.13", 19 | "validator": "^12.1.0" 20 | }, 21 | "devDependencies": { 22 | "@babel/core": "^7.7.4", 23 | "@babel/preset-env": "^7.7.4", 24 | "@babel/preset-typescript": "^7.7.4", 25 | "@commitlint/cli": "^8.2.0", 26 | "@commitlint/config-conventional": "^8.2.0", 27 | "@semantic-release/changelog": "^3.0.6", 28 | "@semantic-release/git": "^7.0.18", 29 | "@types/node": "^12.12.14", 30 | "@types/validator": "^12.0.1", 31 | "@types/webpack-env": "^1.14.1", 32 | "babel-jest": "^24.9.0", 33 | "git-cz": "^3.3.0", 34 | "husky": "^3.1.0", 35 | "jest": "^24.9.0", 36 | "prettier": "^1.19.1", 37 | "pretty-quick": "^2.0.1", 38 | "semantic-release": "^15.13.31", 39 | "ts-jest": "^24.2.0", 40 | "typescript": "^3.7.2" 41 | }, 42 | "peerDependencies": { 43 | "vue": "^2.5.17", 44 | "vue-router": "^3.0.1", 45 | "vuex": "^3.0.1" 46 | }, 47 | "scripts": { 48 | "build": "tsc", 49 | "watch": "tsc --watch", 50 | "test": "jest", 51 | "commit": "npx git-cz", 52 | "installPeers": "npm install vue vue-router vuex --no-save", 53 | "release": "semantic-release" 54 | }, 55 | "husky": { 56 | "hooks": { 57 | "pre-commit": "pretty-quick --staged", 58 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 59 | } 60 | }, 61 | "files": [ 62 | "lib", 63 | "src", 64 | "stubs", 65 | "components", 66 | "BaseLayout.vue", 67 | "Alerts.vue" 68 | ], 69 | "sideEffects": [ 70 | "*.vue" 71 | ] 72 | } 73 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |

> **Note:** This repository contains the core code of the Varie framework. Visit the main [Varie Repository](https://github.com/variejs/varie) to get started. ## About Varie Varie is a Typescript framework for rapidly building powerful and elegant Vue.js applications. Bringing in concepts from other languages to speed up your development. Whether working in a small / large teams, Varie elevates your starting point to ramp into development. ### Notable Features - Validation - CLI Plugin - Fluent Router - State Management - Request Middleware - Authentication System - Customizable Modern Bundler - Dependency Injection System (DI) ## License The Varie framework is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). -------------------------------------------------------------------------------- /release.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | "@semantic-release/commit-analyzer", 4 | "@semantic-release/release-notes-generator", 5 | [ 6 | "@semantic-release/changelog", 7 | { 8 | changelogTitle: 9 | "# Changelog\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.", 10 | }, 11 | ], 12 | [ 13 | "@semantic-release/npm", 14 | ], 15 | [ 16 | "@semantic-release/github", 17 | ], 18 | [ 19 | "@semantic-release/git", 20 | { 21 | message: 22 | "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}", 23 | }, 24 | ], 25 | ], 26 | }; 27 | -------------------------------------------------------------------------------- /src/config/ConfigInterface.ts: -------------------------------------------------------------------------------- 1 | export default interface ConfigInterface { 2 | set(parameter: string, value: any): any; 3 | get(parameter: string, defaultValue?: string | null): any; 4 | } 5 | -------------------------------------------------------------------------------- /src/config/ConfigService.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from "inversify"; 2 | import ConfigInterface from "./ConfigInterface"; 3 | import { getByDot, setByDot } from "./../utilities"; 4 | 5 | declare const __ENV_VARIABLES__: object; 6 | 7 | @injectable() 8 | export default class Config implements ConfigInterface { 9 | protected configs = __ENV_VARIABLES__; 10 | 11 | constructor() { 12 | let files = require.context("@config", true, /^\.\/.*\.(ts)$/); 13 | 14 | for (let filename of files.keys()) { 15 | let configName = filename 16 | .replace(/^\.\//, "") 17 | .replace(/\/$/, "") 18 | .replace(/\.js/, "") 19 | .replace(/\.ts/, ""); 20 | 21 | this.configs[configName] = Object.assign( 22 | {}, 23 | files(filename).default, 24 | this.configs[configName], 25 | ); 26 | } 27 | } 28 | 29 | public get(path: string, defaultValue: any) { 30 | return getByDot(this.configs, path, defaultValue); 31 | } 32 | 33 | public set(path: string, value: any) { 34 | return setByDot(this.configs, path, value); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/config/ConfigServiceProvider.ts: -------------------------------------------------------------------------------- 1 | declare const global: any; 2 | import ConfigService from "./ConfigService"; 3 | import ConfigInterface from "./ConfigInterface"; 4 | import ServiceProvider from "../support/ServiceProvider"; 5 | 6 | export default class ConfigServiceProvider extends ServiceProvider { 7 | public register() { 8 | this.app.singleton("ConfigService", ConfigService); 9 | global.$config = this.app.make("ConfigService"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/cookies/CookieInterface.ts: -------------------------------------------------------------------------------- 1 | export default interface CookieInterface { 2 | get(name: string): any; 3 | set( 4 | name: string, 5 | value: any, 6 | days?: number, 7 | path?: string, 8 | domain?: string, 9 | secure?: boolean, 10 | ); 11 | remove(name: string, path?: string, domain?: string); 12 | hasItem(name: string): boolean; 13 | } 14 | -------------------------------------------------------------------------------- /src/cookies/CookieService.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from "inversify"; 2 | import CookieInterface from "./CookieInterface"; 3 | 4 | // https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie/Simple_document.cookie_framework 5 | 6 | @injectable() 7 | export default class CookieService implements CookieInterface { 8 | public get(name: string) { 9 | if (!name) { 10 | return null; 11 | } 12 | return ( 13 | decodeURIComponent( 14 | document.cookie.replace( 15 | new RegExp( 16 | "(?:(?:^|.*;)\\s*" + 17 | encodeURIComponent(name).replace(/[\-\.\+\*]/g, "\\$&") + 18 | "\\s*\\=\\s*([^;]*).*$)|^.*$", 19 | ), 20 | "$1", 21 | ), 22 | ) || null 23 | ); 24 | } 25 | 26 | public set( 27 | name: string, 28 | value: any, 29 | days: number = 1, 30 | path: string = "/", 31 | domain?: string, 32 | secure?: boolean, 33 | ) { 34 | let expires = new Date(); 35 | expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000); 36 | if (!name || /^(?:expires|max\-age|path|domain|secure)$/i.test(name)) { 37 | return false; 38 | } 39 | document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent( 40 | value, 41 | )}; expires=${expires.toUTCString()}${domain ? "; domain=" + domain : ""}${ 42 | path ? "; path=" + path : "" 43 | }${secure ? "; secure" : ""}`; 44 | } 45 | 46 | public remove(name: string, path?: string, domain?: string) { 47 | if (!this.hasItem(name)) { 48 | return false; 49 | } 50 | document.cookie = 51 | encodeURIComponent(name) + 52 | "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + 53 | (domain ? "; domain=" + domain : "") + 54 | (path ? "; path=" + path : ""); 55 | } 56 | 57 | public hasItem(name: string) { 58 | if (!name || /^(?:expires|max\-age|path|domain|secure)$/i.test(name)) { 59 | return false; 60 | } 61 | return new RegExp( 62 | "(?:^|;\\s*)" + 63 | encodeURIComponent(name).replace(/[\-\.\+\*]/g, "\\$&") + 64 | "\\s*\\=", 65 | ).test(document.cookie); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/cookies/CookieServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import CookieService from "./CookieService"; 2 | import CookieInterface from "./CookieInterface"; 3 | import ServiceProvider from "../support/ServiceProvider"; 4 | 5 | export default class CookieServiceProvider extends ServiceProvider { 6 | public register() { 7 | this.app.singleton("CookieService", CookieService); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/foundation/Application.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import "reflect-metadata"; 3 | import { Container } from "inversify"; 4 | import ContainerMixin from "./ContainerMixin"; 5 | import ApplicationInterface from "./ApplicationInterface"; 6 | import ServiceProviderInterface from "../support/ServiceProviderInterface"; 7 | 8 | declare const global: any; 9 | 10 | export default class Application implements ApplicationInterface { 11 | protected app; 12 | 13 | private container: Container; 14 | private providers: Array = []; 15 | private appProviders = require("@config/app").default.providers; 16 | 17 | constructor() { 18 | this.app = this; 19 | global.$app = this.app; 20 | Vue.prototype["$app"] = this.app; 21 | this.container = new Container(); 22 | this.constant("app", this.app); 23 | } 24 | 25 | public async boot(): Promise { 26 | new ContainerMixin().registerMixin(this); 27 | await this.registerConfiguredProviders(); 28 | await this.bootProviders(); 29 | return this; 30 | } 31 | 32 | public bind(abstract: string, concrete: AnyClass) { 33 | this.container.bind(abstract).to(concrete); 34 | } 35 | 36 | public singleton(abstract: string, concrete: AnyClass) { 37 | this.container 38 | .bind(abstract) 39 | .to(concrete) 40 | .inSingletonScope(); 41 | } 42 | 43 | public constant(key: string, constant: any) { 44 | this.container.bind(key).toConstantValue(constant); 45 | } 46 | 47 | public make(abstract: string): T { 48 | return this.container.get(abstract); 49 | } 50 | 51 | public addProvider(provider) { 52 | this.providers.push(provider); 53 | } 54 | 55 | public isBound(key) { 56 | return this.container.isBound(key); 57 | } 58 | 59 | private async registerConfiguredProviders() { 60 | for (let provider in this.appProviders) { 61 | await this.getAppProvider(provider); 62 | } 63 | } 64 | 65 | private async getAppProvider( 66 | provider: string, 67 | ): Promise { 68 | return new this.appProviders[provider](this.app).register(); 69 | } 70 | 71 | private async bootProviders() { 72 | for (const provider in this.providers) { 73 | await this.providers[provider].boot(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/foundation/ApplicationInterface.ts: -------------------------------------------------------------------------------- 1 | import ServiceProvider from "./../support/ServiceProvider"; 2 | 3 | export default interface ApplicationInterface { 4 | boot(): any; 5 | make(abstract: string): T; 6 | constant(key: string, constant: any): void; 7 | bind(abstract: string, concrete: any): void; 8 | singleton(abstract: string, concrete: any): void; 9 | isBound(key: string): boolean; 10 | addProvider(serviceProvider: ServiceProvider); 11 | } 12 | -------------------------------------------------------------------------------- /src/foundation/ContainerMixin.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import camelize from "../utilities/camelize"; 3 | import ApplicationInterface from "./ApplicationInterface"; 4 | 5 | export default class ContainerMixin { 6 | registerMixin(app: ApplicationInterface) { 7 | Vue.mixin({ 8 | beforeCreate() { 9 | let services = this.$options.$inject || []; 10 | services.forEach((service: string) => { 11 | this[camelize(service)] = app.make(service); 12 | }); 13 | }, 14 | }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/globals.ts: -------------------------------------------------------------------------------- 1 | import ConfigInterface from "./config/ConfigInterface"; 2 | import ApplicationInterface from "./foundation/ApplicationInterface"; 3 | 4 | declare global { 5 | const $config: ConfigInterface; 6 | const $app: ApplicationInterface; 7 | 8 | type AnyClass = { new (): any }; 9 | } 10 | -------------------------------------------------------------------------------- /src/http/AxiosHttpService.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; 2 | import { inject, injectable } from "inversify"; 3 | import HttpServiceInterface from "./HttpServiceInterface"; 4 | import ApplicationInterface from "../foundation/ApplicationInterface"; 5 | import HttpMiddlewareInterface from "./interfaces/HttpMiddlewareInterface"; 6 | 7 | @injectable() 8 | export default class AxiosHttpService implements HttpServiceInterface { 9 | protected middleware = {}; 10 | protected axios: AxiosInstance; 11 | protected app: ApplicationInterface; 12 | 13 | constructor( 14 | @inject("app") app: ApplicationInterface, 15 | @inject("ConfigService") configService, 16 | ) { 17 | this.app = app; 18 | this.axios = axios.create(configService.get("http")); 19 | } 20 | 21 | public delete(url: string, config = {}) { 22 | return this.axios.delete(url, config); 23 | } 24 | 25 | public get(url: string, config = {}) { 26 | return this.axios.get(url, config); 27 | } 28 | 29 | public head(url: string, config = {}) { 30 | return this.axios.head(url, config); 31 | } 32 | 33 | public options(url: string, config = {}) { 34 | // https://github.com/axios/axios/pull/2341 35 | // @ts-ignore 36 | return this.axios.options(url, config); 37 | } 38 | 39 | public post(url: string, data: object, config = {}) { 40 | return this.axios.post(url, data, config); 41 | } 42 | 43 | public put(url: string, data: object, config = {}) { 44 | return this.axios.put(url, data, config); 45 | } 46 | 47 | public patch(url: string, data: object, config = {}) { 48 | return this.axios.patch(url, data, config); 49 | } 50 | 51 | public request(config = {}) { 52 | return this.axios.request(config); 53 | } 54 | 55 | public registerMiddleware(Middleware: new () => HttpMiddlewareInterface) { 56 | let middlewareName = `httpMiddleware${Middleware.name}`; 57 | this.app.bind(middlewareName, Middleware); 58 | let middleware = this.app.make(middlewareName); 59 | this.middleware[middleware.constructor.name] = { 60 | request: this.axios.interceptors.request.use((config) => { 61 | if (middleware.request) { 62 | return middleware.request(config); 63 | } 64 | return config; 65 | }), 66 | response: this.axios.interceptors.response.use( 67 | function(response) { 68 | if (middleware.response) { 69 | return middleware.response(response); 70 | } 71 | return response; 72 | }, 73 | function(error) { 74 | if (middleware.responseError) { 75 | return Promise.reject(middleware.responseError(error)); 76 | } 77 | return Promise.reject(error); 78 | }, 79 | ), 80 | }; 81 | } 82 | 83 | public unregisterMiddleware(Middleware: new () => HttpMiddlewareInterface) { 84 | let middleware = new Middleware().constructor.name; 85 | axios.interceptors.request.eject(this.middleware[middleware].request); 86 | axios.interceptors.response.eject(this.middleware[middleware].response); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/http/HttpServiceInterface.ts: -------------------------------------------------------------------------------- 1 | import HttpResponseInterface from "./interfaces/HttpResponseInterface"; 2 | import HttpMiddlewareInterface from "./interfaces/HttpMiddlewareInterface"; 3 | import HttpRequestConfigInterface from "./interfaces/HttpRequestConfigInterface"; 4 | 5 | export default interface HttpServiceInterface { 6 | get( 7 | url: string, 8 | config?: HttpRequestConfigInterface, 9 | ): Promise; 10 | put( 11 | url: string, 12 | data: object, 13 | config?: HttpRequestConfigInterface, 14 | ): Promise; 15 | post( 16 | url: string, 17 | data?: object, 18 | config?: HttpRequestConfigInterface, 19 | ): Promise; 20 | patch( 21 | url: string, 22 | data: object, 23 | config?: HttpRequestConfigInterface, 24 | ): Promise; 25 | delete( 26 | url: string, 27 | config?: HttpRequestConfigInterface, 28 | ): Promise; 29 | head( 30 | url: string, 31 | config?: HttpRequestConfigInterface, 32 | ): Promise; 33 | options(url: string, config?: HttpRequestConfigInterface); 34 | request(config?: HttpRequestConfigInterface); 35 | registerMiddleware(middleware: new () => HttpMiddlewareInterface); 36 | unregisterMiddleware(middleware: new () => HttpMiddlewareInterface); 37 | } 38 | -------------------------------------------------------------------------------- /src/http/HttpServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import HttpConfig from "./config"; 2 | import AxiosHttpService from "./AxiosHttpService"; 3 | import ServiceProvider from "../support/ServiceProvider"; 4 | import HttpServiceInterface from "./HttpServiceInterface"; 5 | 6 | export default class HttpServiceProvider extends ServiceProvider { 7 | public boot() { 8 | let $httpService = this.app.make("HttpService"); 9 | require("@app/middleware").default.forEach((middleware) => { 10 | $httpService.registerMiddleware(middleware); 11 | }); 12 | } 13 | 14 | public register() { 15 | this.mergeConfigFrom(HttpConfig, "http"); 16 | this.app.singleton("HttpService", AxiosHttpService); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/http/config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | /* 3 | |-------------------------------------------------------------------------- 4 | | Base URL 5 | |-------------------------------------------------------------------------- 6 | | 7 | | Sometimes you need to setup a base url for all your requests 8 | | 9 | */ 10 | baseURL: null, 11 | 12 | /* 13 | |-------------------------------------------------------------------------- 14 | | Customized Headers 15 | |-------------------------------------------------------------------------- 16 | | 17 | | If you need to attach headers with every requests you should do that here 18 | | 19 | */ 20 | headers: { 21 | common: { 22 | "X-Requested-With": "XMLHttpRequest", 23 | }, 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /src/http/interfaces/HttpErrorInterface.ts: -------------------------------------------------------------------------------- 1 | import HttpRequestConfigInterface from "./HttpRequestConfigInterface"; 2 | import HttpResponseInterface from "./HttpResponseInterface"; 3 | 4 | export default interface HttpRequestInterface extends Error { 5 | config: HttpRequestConfigInterface; 6 | code?: string; 7 | request?: any; 8 | response?: HttpResponseInterface; 9 | } 10 | -------------------------------------------------------------------------------- /src/http/interfaces/HttpMiddlewareInterface.ts: -------------------------------------------------------------------------------- 1 | import HttpErrorInterface from "./HttpErrorInterface"; 2 | import HttpResponseInterface from "./HttpResponseInterface"; 3 | import HttpRequestConfigInterface from "./HttpRequestConfigInterface"; 4 | 5 | export default interface HttpMiddlewareInterface { 6 | request( 7 | config: HttpRequestConfigInterface, 8 | ): HttpRequestConfigInterface | Promise; 9 | response( 10 | response: HttpResponseInterface, 11 | ): HttpResponseInterface | Promise; 12 | responseError(responseError: HttpErrorInterface); 13 | } 14 | -------------------------------------------------------------------------------- /src/http/interfaces/HttpRequestConfigInterface.ts: -------------------------------------------------------------------------------- 1 | export default interface HttpRequestConfigInterface { 2 | url?: string; 3 | method?: string; 4 | baseURL?: string; 5 | headers?: any; 6 | params?: any; 7 | paramsSerializer?: (params: any) => string; 8 | data?: any; 9 | timeout?: number; 10 | withCredentials?: boolean; 11 | responseType?: string; 12 | xsrfCookieName?: string; 13 | xsrfHeaderName?: string; 14 | maxContentLength?: number; 15 | validateStatus?: (status: number) => boolean; 16 | maxRedirects?: number; 17 | httpAgent?: any; 18 | httpsAgent?: any; 19 | } 20 | -------------------------------------------------------------------------------- /src/http/interfaces/HttpResponseInterface.ts: -------------------------------------------------------------------------------- 1 | import HttpRequestConfigInterface from "./HttpRequestConfigInterface"; 2 | 3 | export default interface HttpResponseInterface { 4 | data: T; 5 | status: number; 6 | statusText: string; 7 | headers: any; 8 | config: HttpRequestConfigInterface; 9 | request?: any; 10 | } 11 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import * as utilities from "./utilities"; 2 | import Application from "./foundation/Application"; 3 | 4 | // Core Service Providers 5 | import HttpServiceProvider from "./http/HttpServiceProvider"; 6 | import StateServiceProvider from "./state/StateServiceProvider"; 7 | import ConfigServiceProvider from "./config/ConfigServiceProvider"; 8 | import CookieServiceProvider from "./cookies/CookieServiceProvider"; 9 | import RoutingServiceProvider from "./routing/RoutingServiceProvider"; 10 | import StorageServiceProvider from "./storage/StorageServiceProvider"; 11 | 12 | // Support Service Providers 13 | import Model from "./support/Model"; 14 | import ServiceProvider from "./support/ServiceProvider"; 15 | 16 | // Plugin Service Providers 17 | import FormServiceProvider from "./plugins/forms/FormServiceProvider"; 18 | import AlertServiceProvider from "./plugins/alerts/AlertServiceProvider"; 19 | import ValidationServiceProvider from "./validation/ValidationServiceProvider"; 20 | 21 | // Auto Register Service Providers 22 | import AutoRegisterMixinServiceProvider from "./plugins/autoRegisterMixins/AutoRegisterMixinServiceProvider"; 23 | import AutoRegisterFilterServiceProvider from "./plugins/autoRegisterFilters/AutoRegisterFilterServiceProvider"; 24 | import AutoRegisterLayoutServiceProvider from "./plugins/autoRegisterLayouts/AutoRegisterLayoutServiceProvider"; 25 | import AutoRegisterComponentServiceProvider from "./plugins/autoRegisterComponents/AutoRegisterComponentServiceProvider"; 26 | import AutoRegisterDirectiveServiceProvider from "./plugins/autoRegisterDirectives/AutoRegisterDirectiveServiceProvider"; 27 | 28 | export { 29 | Model, 30 | utilities, 31 | Application, 32 | ServiceProvider, 33 | FormServiceProvider, 34 | HttpServiceProvider, 35 | StateServiceProvider, 36 | AlertServiceProvider, 37 | ConfigServiceProvider, 38 | CookieServiceProvider, 39 | RoutingServiceProvider, 40 | StorageServiceProvider, 41 | ValidationServiceProvider, 42 | AutoRegisterMixinServiceProvider, 43 | AutoRegisterFilterServiceProvider, 44 | AutoRegisterLayoutServiceProvider, 45 | AutoRegisterComponentServiceProvider, 46 | AutoRegisterDirectiveServiceProvider, 47 | }; 48 | -------------------------------------------------------------------------------- /src/plugins/alerts/AlertService.ts: -------------------------------------------------------------------------------- 1 | import { Store } from "vuex"; 2 | import { inject, injectable } from "inversify"; 3 | import ConfigInterface from "../../config/ConfigInterface"; 4 | import StateServiceInterface from "../../state/StateServiceInterface"; 5 | 6 | @injectable() 7 | class AlertService { 8 | protected store: Store; 9 | protected configService: { 10 | duration: number; 11 | }; 12 | 13 | constructor( 14 | @inject("ConfigService") $config: ConfigInterface, 15 | @inject("StateService") stateService: StateServiceInterface, 16 | ) { 17 | this.store = stateService.getStore(); 18 | this.configService = $config.get("alerts"); 19 | } 20 | 21 | public error(message: string, title: string = "Error", duration?: number) { 22 | this.makeAlert(message, title, duration, "error"); 23 | } 24 | 25 | public info(message: string, title: string = "Info", duration?: number) { 26 | this.makeAlert(message, title, duration, "info"); 27 | } 28 | 29 | public success( 30 | message: string, 31 | title: string = "Success", 32 | duration?: number, 33 | ) { 34 | this.makeAlert(message, title, duration, "success"); 35 | } 36 | 37 | public warning( 38 | message: string, 39 | title: string = "Warning", 40 | duration?: number, 41 | ) { 42 | this.makeAlert(message, title, duration, "warning"); 43 | } 44 | 45 | protected makeAlert( 46 | message: string, 47 | title: string, 48 | duration?: number, 49 | severity?: string, 50 | ) { 51 | if (duration === undefined) { 52 | duration = this.configService.duration; 53 | } 54 | this.store.dispatch("varie/alerts/add", { 55 | message: message, 56 | duration: duration, 57 | severity: severity, 58 | title: title ? title : `${severity}!!`, 59 | }); 60 | } 61 | } 62 | 63 | export default AlertService; 64 | -------------------------------------------------------------------------------- /src/plugins/alerts/AlertServiceInterface.ts: -------------------------------------------------------------------------------- 1 | export default interface AlertServiceInterface { 2 | showError(message: string, title?: string, duration?: number): void; 3 | showInfo(message: string, title?: string, duration?: number): void; 4 | showSuccess(message: string, title?: string, duration?: number): void; 5 | showWarning(message: string, title?: string, duration?: number): void; 6 | } 7 | -------------------------------------------------------------------------------- /src/plugins/alerts/AlertServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Alerts from "./Alerts"; 3 | import config from "./config"; 4 | import AlertService from "./AlertService"; 5 | import VuexService from "../../state/VuexService"; 6 | import AlertServiceInterface from "./AlertServiceInterface"; 7 | import ServiceProvider from "../../support/ServiceProvider"; 8 | 9 | export default class AlertServiceProvider extends ServiceProvider { 10 | public boot() { 11 | Vue.use(new Alerts(this.app.make("ConfigService")), { 12 | store: this.app.make("StateService").getStore(), 13 | service: this.app.make("AlertService"), 14 | }); 15 | } 16 | 17 | public register() { 18 | this.mergeConfigFrom(config, "alerts"); 19 | this.app.singleton("AlertService", AlertService); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/plugins/alerts/Alerts.ts: -------------------------------------------------------------------------------- 1 | import AlertService from "./AlertService"; 2 | import { VueConstructor } from "vue/types/vue"; 3 | import AlertStore from "./alert-store/AlertStore"; 4 | import ConfigInterface from "../../config/ConfigInterface"; 5 | 6 | export default class Alerts { 7 | protected config: { 8 | duration: number; 9 | }; 10 | 11 | constructor($config: ConfigInterface) { 12 | this.config = $config.get("alerts"); 13 | } 14 | 15 | public install(Vue: VueConstructor, { store, service }) { 16 | store.registerModule(["varie", "alerts"], new AlertStore()); 17 | Vue.mixin({ 18 | computed: { 19 | alertService: (): AlertService => { 20 | return service; 21 | }, 22 | }, 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/plugins/alerts/alert-store/AlertStore.ts: -------------------------------------------------------------------------------- 1 | import state from "./state"; 2 | import Actions from "./actions"; 3 | import Mutations from "./mutations"; 4 | import { injectable } from "inversify"; 5 | 6 | @injectable() 7 | export default class AlertStore { 8 | public name; 9 | public state; 10 | public actions; 11 | public mutations; 12 | public namespaced; 13 | 14 | constructor() { 15 | this.state = state; 16 | this.name = "alerts"; 17 | this.namespaced = true; 18 | this.actions = new Actions(); 19 | this.mutations = new Mutations(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/plugins/alerts/alert-store/actions.ts: -------------------------------------------------------------------------------- 1 | import { ActionContext } from "vuex"; 2 | // @ts-ignore 3 | import RootState from "@store/rootState"; 4 | import { AlertState } from "./stateInterface"; 5 | import AlertModel from "./../models/AlertModel"; 6 | 7 | export default class Actions { 8 | public add = ( 9 | context: ActionContext, 10 | alert: AlertModel, 11 | ) => { 12 | context.commit("add", alert); 13 | }; 14 | 15 | public remove = ( 16 | context: ActionContext, 17 | alert: AlertModel, 18 | ) => { 19 | context.commit("remove", alert); 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/plugins/alerts/alert-store/mutations.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import { AlertState } from "./stateInterface"; 3 | import AlertModel from "./../models/AlertModel"; 4 | 5 | export default class Mutations { 6 | public add = (state: AlertState, alert: AlertModel) => { 7 | alert.id = this.guid(); 8 | state.alerts.push(alert); 9 | }; 10 | 11 | public remove = (state: AlertState, alert: AlertModel) => { 12 | Vue.set( 13 | state, 14 | "alerts", 15 | state.alerts.filter((tempAlert) => { 16 | return alert.id !== tempAlert.id; 17 | }), 18 | ); 19 | }; 20 | 21 | // TODO - this needs to be moved out 22 | protected guid() { 23 | function s4() { 24 | return Math.floor((1 + Math.random()) * 0x10000) 25 | .toString(16) 26 | .substring(1); 27 | } 28 | return ( 29 | s4() + 30 | s4() + 31 | "-" + 32 | s4() + 33 | "-" + 34 | s4() + 35 | "-" + 36 | s4() + 37 | "-" + 38 | s4() + 39 | s4() + 40 | s4() 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/plugins/alerts/alert-store/state.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | alerts: [], 3 | }; 4 | -------------------------------------------------------------------------------- /src/plugins/alerts/alert-store/stateInterface.ts: -------------------------------------------------------------------------------- 1 | import AlertModel from "./../models/AlertModel"; 2 | export interface AlertState { 3 | alerts: Array; 4 | } 5 | -------------------------------------------------------------------------------- /src/plugins/alerts/config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | /* 3 | |-------------------------------------------------------------------------- 4 | | Duration 5 | |-------------------------------------------------------------------------- 6 | | 7 | | How long a alert will show up, 0 will make it a forever living alert. 8 | | 9 | */ 10 | 11 | duration: 0, 12 | }; 13 | -------------------------------------------------------------------------------- /src/plugins/alerts/models/AlertModel.ts: -------------------------------------------------------------------------------- 1 | export default interface AlertModel { 2 | title: string; 3 | message: string; 4 | severity: string; 5 | id: null | number | string; 6 | duration: number | undefined | null; 7 | } 8 | -------------------------------------------------------------------------------- /src/plugins/autoRegisterComponents/AutoRegisterComponentServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import dashify from "../../utilities/dashify"; 3 | import ServiceProvider from "../../support/ServiceProvider"; 4 | 5 | export default class AutoRegisterComponentServiceProvider extends ServiceProvider { 6 | public register() {} 7 | 8 | public boot() { 9 | let files = require.context("@components", true, /^\.\/.*\.(vue)$/); 10 | files.keys().forEach((filename) => { 11 | Vue.component(this.getComponentName(filename), files(filename).default); 12 | }); 13 | } 14 | 15 | protected getComponentName(filename: string) { 16 | return dashify(filename.replace(".vue", "")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/plugins/autoRegisterDirectives/AutoRegisterDirectiveServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import ServiceProvider from "../../support/ServiceProvider"; 2 | 3 | export default class AutoRegisterDirectiveServiceProvider extends ServiceProvider { 4 | public register() {} 5 | 6 | public boot() { 7 | let files = require.context("@app/directives", true, /^\.\/.*\.(ts|js)$/); 8 | files.keys().forEach((filename) => { 9 | files(filename); 10 | }); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/plugins/autoRegisterFilters/AutoRegisterFilterServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import camelize from "../../utilities/camelize"; 3 | import ServiceProvider from "../../support/ServiceProvider"; 4 | 5 | export default class AutoRegisterFilterServiceProvider extends ServiceProvider { 6 | public register() {} 7 | 8 | public boot() { 9 | let files = require.context("@app/filters", true, /^\.\/.*\.(ts|js)$/); 10 | files.keys().forEach((filename) => { 11 | Vue.filter(this.getFilterName(filename), files(filename).default); 12 | }); 13 | } 14 | 15 | protected getFilterName(filename: string) { 16 | return camelize(filename.replace(".ts", "")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/plugins/autoRegisterLayouts/AutoRegisterLayoutServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import dashify from "../../utilities/dashify"; 3 | import ServiceProvider from "../../support/ServiceProvider"; 4 | 5 | export default class AutoRegisterLayoutServiceProvider extends ServiceProvider { 6 | public register() {} 7 | 8 | public boot() { 9 | let files = require.context("@views/layouts", false, /^\.\/.*\.(vue)$/); 10 | files.keys().forEach((filename) => { 11 | Vue.component(this.getComponentName(filename), files(filename).default); 12 | }); 13 | } 14 | 15 | protected getComponentName(filename: string) { 16 | return `${dashify(filename.replace(".vue", ""))}-layout`; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/plugins/autoRegisterMixins/AutoRegisterMixinServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import ServiceProvider from "../../support/ServiceProvider"; 3 | 4 | export default class AutoRegisterMixinServiceProvider extends ServiceProvider { 5 | public register() {} 6 | 7 | public boot() { 8 | let files = require.context("@app/mixins", true, /^\.\/.*\.(ts|js)$/); 9 | files.keys().forEach((filename) => { 10 | Vue.mixin(files(filename)); 11 | }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/plugins/forms/Form.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import filterEmpty from "./../../utilities/filterEmpty"; 3 | import ValidationServiceInterface from "../../validation/ValidationServiceInterface"; 4 | 5 | // TODO - we could use setters / getters to remove _'s for public things 6 | class Form { 7 | public _rules: object = {}; 8 | public _messages: object = {}; 9 | 10 | protected _validator; 11 | protected _initialData: any; 12 | protected _originalData: any; 13 | 14 | constructor(data: object, validationService?: ValidationServiceInterface) { 15 | if (validationService) { 16 | this._validator = validationService; 17 | } 18 | this.fill(data); 19 | this.setAsOriginalData(); 20 | this._initialData = this.data(false); 21 | } 22 | 23 | public fill(data) { 24 | for (let key in data) { 25 | Vue.set(this, key, data[key]); 26 | } 27 | return this; 28 | } 29 | 30 | public merge(data) { 31 | for (let key in data) { 32 | if (data[key] && this.hasOwnProperty(key)) { 33 | Vue.set(this, key, data[key]); 34 | } 35 | } 36 | return this; 37 | } 38 | 39 | public validation({ rules, messages }) { 40 | this._rules = rules; 41 | this._messages = messages; 42 | return this; 43 | } 44 | 45 | public isValid() { 46 | if (this._validator) { 47 | let errors = this._validator.validate( 48 | this.data(), 49 | this._rules, 50 | this._messages, 51 | ); 52 | if (Object.keys(errors).length) { 53 | return false; 54 | } 55 | } 56 | return true; 57 | } 58 | 59 | public data(removeEmpty = true) { 60 | let data = {}; 61 | let tempData = Object.assign({}, this); 62 | 63 | delete tempData._rules; 64 | delete tempData._messages; 65 | delete tempData._validator; 66 | delete tempData._initialData; 67 | delete tempData._originalData; 68 | 69 | for (let field in tempData) { 70 | data[`${field}`] = this[field]; 71 | } 72 | 73 | if (removeEmpty) { 74 | return filterEmpty(data); 75 | } 76 | return data; 77 | } 78 | 79 | public setAsOriginalData() { 80 | this._originalData = this.data(); 81 | return this; 82 | } 83 | 84 | public reset() { 85 | for (let field in this.data()) { 86 | this.remove(field); 87 | } 88 | this.fill(this._originalData); 89 | return this; 90 | } 91 | 92 | initial() { 93 | this.fill(this._initialData).setAsOriginalData(); 94 | return this; 95 | } 96 | 97 | public remove(key) { 98 | Vue.delete(this, key); 99 | return this; 100 | } 101 | 102 | public errors() { 103 | return this._validator.validate(this.data(), this._rules, this._messages); 104 | } 105 | 106 | public isDirty(property?) { 107 | let data = this.data(); 108 | let originalData = this._originalData; 109 | if (property) { 110 | return ( 111 | (data.hasOwnProperty(property) && 112 | !originalData.hasOwnProperty(property)) || 113 | data[property] !== originalData[property] 114 | ); 115 | } 116 | return JSON.stringify(data) !== JSON.stringify(originalData); 117 | } 118 | } 119 | 120 | export default Form; 121 | -------------------------------------------------------------------------------- /src/plugins/forms/FormServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import { PluginObject } from "vue"; 3 | import FormsPlugin from "./FormsPlugin"; 4 | import ServiceProvider from "../../support/ServiceProvider"; 5 | 6 | export default class FormServiceProvider extends ServiceProvider { 7 | public boot() { 8 | Vue.use(this.app.make>("FormService")); 9 | } 10 | public register() { 11 | this.app.singleton("FormService", FormsPlugin); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/plugins/forms/FormsPlugin.ts: -------------------------------------------------------------------------------- 1 | import Form from "./Form"; 2 | import { inject, injectable } from "inversify"; 3 | import { VueConstructor } from "vue/types/vue"; 4 | 5 | @injectable() 6 | class Forms { 7 | @inject("ValidationService") protected validateService; 8 | 9 | public install(Vue: VueConstructor) { 10 | Vue.mixin({ 11 | methods: { 12 | createForm: (data: object) => { 13 | return new Form(data, this.validateService); 14 | }, 15 | }, 16 | }); 17 | } 18 | } 19 | 20 | export default Forms; 21 | -------------------------------------------------------------------------------- /src/routing/Route.ts: -------------------------------------------------------------------------------- 1 | export default class Route { 2 | public path; 3 | public name; 4 | public alias; 5 | public group; 6 | public props; 7 | public components; 8 | public meta: { 9 | data?: object; 10 | layout?: string; 11 | middleware?: Array; 12 | } = {}; 13 | 14 | protected component; 15 | 16 | constructor( 17 | path: string, 18 | components: string | object | Array, 19 | props: (() => void) | boolean | object = true, 20 | ) { 21 | this.path = path; 22 | this.props = props; 23 | 24 | this.registerComponents(components); 25 | } 26 | 27 | public setName(name: string): this { 28 | this.name = name; 29 | return this; 30 | } 31 | 32 | public setMeta(data): this { 33 | this.meta = Object.assign(this.meta, data); 34 | return this; 35 | } 36 | 37 | public setAlias(alias) { 38 | this.alias = alias; 39 | return this; 40 | } 41 | 42 | public setLayout(layout) { 43 | this.meta.layout = layout; 44 | return this; 45 | } 46 | 47 | protected registerComponents(components) { 48 | if (typeof components === "object" && !components.__file) { 49 | this.components = {}; 50 | for (let name in components) { 51 | this.components[name] = components[name]; 52 | } 53 | } else { 54 | this.component = components; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/routing/RouteMiddlewareInterface.ts: -------------------------------------------------------------------------------- 1 | import { Route, Location } from "vue-router"; 2 | 3 | export default interface RouteMiddlewareInterface { 4 | handler(to: Route, from: Route, next: (route?: Location) => void): void; 5 | } 6 | -------------------------------------------------------------------------------- /src/routing/RouterInterface.ts: -------------------------------------------------------------------------------- 1 | import Route from "./Route"; 2 | 3 | export default interface RouterInterface { 4 | getRouter(): any; 5 | route( 6 | path: string, 7 | component: object, 8 | props?: (() => void) | boolean | object, 9 | ): Route; 10 | group(routes: Function): this; 11 | middleware(middleware: Array): this; 12 | prefix(prefix: string): this; 13 | area(area: object): this; 14 | redirect(path: string, redirect: string): this; 15 | layout(layout: string): this; 16 | data(data: object): this; 17 | // TODO - this should not be any 18 | register(routes: any, ...services: Array): this; 19 | } 20 | -------------------------------------------------------------------------------- /src/routing/RoutesInterface.ts: -------------------------------------------------------------------------------- 1 | export default interface RoutesInterface { 2 | register(); 3 | } 4 | -------------------------------------------------------------------------------- /src/routing/RoutingServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import RouterConfig from "./config"; 2 | import VueRouterService from "./VueRouterService"; 3 | import ServiceProvider from "../support/ServiceProvider"; 4 | 5 | export default class RoutingServiceProvider extends ServiceProvider { 6 | public $router; 7 | 8 | public boot() { 9 | this.$router = this.app.make("RouterService"); 10 | 11 | // @ts-ignore 12 | if (typeof this.map === "function") { 13 | // @ts-ignore 14 | this.map(); 15 | } else { 16 | throw "Your routing service provider must have a map function."; 17 | } 18 | 19 | this.$router.buildRouter(); 20 | } 21 | 22 | public register() { 23 | this.mergeConfigFrom(RouterConfig, "router"); 24 | this.app.singleton("RouterService", VueRouterService); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/routing/VueRouterService.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Route from "./Route"; 3 | import VueRouter from "vue-router"; 4 | import clone from "./../utilities/clone"; 5 | import { inject, injectable } from "inversify"; 6 | import RouterInterface from "./RouterInterface"; 7 | import ConfigInterface from "../config/ConfigInterface"; 8 | import RouteMiddlewareInterface from "./RouteMiddlewareInterface"; 9 | import ApplicationInterface from "../foundation/ApplicationInterface"; 10 | 11 | interface GroupInfo { 12 | path: string; 13 | component: object; 14 | area: null | object; 15 | children: Array; 16 | meta: { 17 | data: object; 18 | layout: string; 19 | middleware: Array; 20 | }; 21 | } 22 | 23 | interface RedirectRoute { 24 | path: string; 25 | redirect: string; 26 | } 27 | 28 | @injectable() 29 | export default class VueRouterService implements RouterInterface { 30 | public router; 31 | public routes: Array = []; 32 | 33 | protected groupInfo; 34 | protected currentGroupLevel = 0; 35 | protected app: ApplicationInterface; 36 | protected groups: Array = []; 37 | protected configService: ConfigInterface; 38 | protected wildCardRoutes: Array = []; 39 | 40 | constructor( 41 | @inject("app") app: ApplicationInterface, 42 | @inject("ConfigService") configService: ConfigInterface, 43 | ) { 44 | this.app = app; 45 | this.configService = configService; 46 | this.resetGroup(); 47 | Vue.use(VueRouter); 48 | } 49 | 50 | public getRouter() { 51 | return this.router; 52 | } 53 | 54 | public register(routes, ...services) { 55 | routes(this, services); 56 | return this; 57 | } 58 | 59 | public buildRouter() { 60 | if (this.wildCardRoutes.length) { 61 | this.wildCardRoutes.forEach((route) => { 62 | if (route.group) { 63 | route.group.children.push(route); 64 | } else { 65 | this.routes.push(route); 66 | } 67 | }); 68 | } 69 | this.router = new VueRouter( 70 | Object.assign({}, this.configService.get("router"), { 71 | routes: this.routes, 72 | }), 73 | ); 74 | 75 | this.setupMiddleware(); 76 | } 77 | 78 | public route(path: string, component: string | object, props = true): Route { 79 | let route = new Route(path, component, props); 80 | 81 | if (this.currentGroupLevel > -1) { 82 | // children routes cannot begin with a `/` as they would not be children 83 | route.path = route.path.replace(/^\/*/g, ""); 84 | 85 | if (route.path === "*") { 86 | route.group = this.groups[this.currentGroupLevel]; 87 | this.wildCardRoutes.push(route); 88 | } else { 89 | this.groups[this.currentGroupLevel].children.push(route); 90 | } 91 | 92 | let tempName = ""; 93 | let groupIndex = this.currentGroupLevel; 94 | for (groupIndex; groupIndex > -1; groupIndex--) { 95 | tempName = 96 | this.groups[groupIndex].path !== "/" 97 | ? this.groups[groupIndex].path + "/" + tempName 98 | : tempName; 99 | } 100 | this.convertRoutePathToRouteName(route, tempName + route.path); 101 | 102 | route.meta.middleware = this.groups[ 103 | this.currentGroupLevel 104 | ].meta.middleware; 105 | 106 | route.meta.data = this.groups[this.currentGroupLevel].meta.data; 107 | 108 | return route; 109 | } 110 | 111 | if (route.path === "*") { 112 | this.wildCardRoutes.push(route); 113 | } else { 114 | route.setMeta(this.groupInfo.meta); 115 | this.routes.push(route); 116 | } 117 | 118 | this.convertRoutePathToRouteName(route); 119 | return route; 120 | } 121 | 122 | protected convertRoutePathToRouteName(route: Route, path?: string) { 123 | path = path ? path : route.path; 124 | if (path) { 125 | route.setName( 126 | path 127 | .replace(/^\/|\/$/g, "") 128 | .replace(/(\/?)(:.*?)(\/|$)/g, ".") 129 | .replace(/^\.|\.$/g, "") 130 | .toLowerCase(), 131 | ); 132 | } 133 | } 134 | 135 | public middleware(middleware: Array) { 136 | this.groupInfo.meta.middleware = this.groupInfo.meta.middleware.concat( 137 | middleware, 138 | ); 139 | return this; 140 | } 141 | 142 | public redirect(path: string, redirect: string) { 143 | this.routes.push({ 144 | path: path, 145 | redirect: redirect, 146 | }); 147 | return this; 148 | } 149 | 150 | public group(routes: Function) { 151 | this.currentGroupLevel++; 152 | this.groups.push(clone(this.groupInfo)); 153 | // Areas only apply to 1 group not all subsequent children groups 154 | delete this.groupInfo.area; 155 | routes(); 156 | this.resetGroup(); 157 | return this; 158 | } 159 | 160 | public area(area: object) { 161 | this.groupInfo.area = area; 162 | return this; 163 | } 164 | 165 | public prefix(prefix: string) { 166 | this.groupInfo.path = prefix || ""; 167 | if (this.currentGroupLevel > -1) { 168 | this.groupInfo.path = this.groupInfo.path.replace(/^\/*/g, ""); 169 | } 170 | return this; 171 | } 172 | 173 | public layout(layout) { 174 | this.groupInfo.meta.layout = layout; 175 | return this; 176 | } 177 | 178 | public data(data) { 179 | this.groupInfo.meta.data = data; 180 | return this; 181 | } 182 | 183 | /** 184 | * We loop through all middleware of that route 185 | * Making sure we resolve them one at a time 186 | */ 187 | public setupMiddleware() { 188 | this.router.beforeResolve((to, from, next) => { 189 | let stopMiddleware = false; 190 | if (to.meta.middleware && to.meta.middleware.length) { 191 | return to.meta.middleware.reduce( 192 | (promise, currentValue, currentIndex) => { 193 | return promise.then(() => { 194 | if (stopMiddleware === false) { 195 | return this.getMiddleware(currentValue).handler( 196 | to, 197 | from, 198 | (options) => { 199 | if (options) { 200 | next(options); 201 | stopMiddleware = true; 202 | return; 203 | } else if (currentIndex === to.meta.middleware.length - 1) { 204 | return next(); 205 | } 206 | }, 207 | ); 208 | } 209 | }); 210 | }, 211 | Promise.resolve(), 212 | ); 213 | } 214 | next(); 215 | }); 216 | } 217 | 218 | protected getMiddleware(middleware) { 219 | let containerMiddlewareName = `routerMiddleware${middleware.name}`; 220 | if (!this.app.isBound(containerMiddlewareName)) { 221 | this.app.bind( 222 | containerMiddlewareName, 223 | middleware, 224 | ); 225 | } 226 | return this.app.make(containerMiddlewareName); 227 | } 228 | 229 | /** 230 | * We build all the group information by looping through each level 231 | * 232 | * Each group will go up in a level with a child group is made 233 | * 234 | * We then go through each grouping and set middleware / areas 235 | * and place the children for that group. 236 | * 237 | * By going up and down for each group we retain the data for the group level 238 | * allowing us to chain in a pretty way 239 | */ 240 | protected resetGroup() { 241 | this.groupInfo = { 242 | path: "/", 243 | meta: { 244 | data: {}, 245 | middleware: [], 246 | layout: this.configService.get("view.defaultLayout", "public"), 247 | }, 248 | area: null, 249 | children: [], 250 | component: { 251 | template: "", 252 | }, 253 | }; 254 | 255 | if (this.groups.length) { 256 | let childGroup = this.groups[this.currentGroupLevel]; 257 | let parentGroup = this.groups[this.currentGroupLevel - 1]; 258 | 259 | if (childGroup.area) { 260 | childGroup.component = childGroup.area; 261 | delete childGroup.area; 262 | } 263 | 264 | if (parentGroup) { 265 | if (childGroup.path === parentGroup.path) { 266 | childGroup.path = ""; 267 | } 268 | this.groupInfo.meta.data = parentGroup.meta.data; 269 | this.groupInfo.meta.layout = parentGroup.meta.layout; 270 | this.groupInfo.meta.middleware = parentGroup.meta.middleware; 271 | parentGroup.children.push(childGroup); 272 | } 273 | 274 | this.groups.splice(this.currentGroupLevel, 1); 275 | 276 | if (this.currentGroupLevel === 0) { 277 | this.routes.push(childGroup); 278 | } 279 | } 280 | 281 | this.currentGroupLevel--; 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /src/routing/config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | /* 3 | |-------------------------------------------------------------------------- 4 | | Mode 5 | |-------------------------------------------------------------------------- 6 | | 7 | | Configure the router mode. 8 | | 9 | | Supported : "hash", "history", "abstract" 10 | | 11 | */ 12 | 13 | mode: "history", 14 | 15 | /* 16 | |-------------------------------------------------------------------------- 17 | | Base 18 | |-------------------------------------------------------------------------- 19 | | 20 | | The base URL of the app. 21 | | 22 | */ 23 | 24 | base: "/", 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | Link active class 29 | |-------------------------------------------------------------------------- 30 | | 31 | | When a link is active this class will be attached to it. 32 | | 33 | */ 34 | 35 | linkActiveClass: "router-link-active", 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Link exact class 40 | |-------------------------------------------------------------------------- 41 | | 42 | | When a link exactly matches the current url this class will be attached to it. 43 | | 44 | */ 45 | 46 | linkExactActiveClass: "router-link-exact-active", 47 | 48 | /* 49 | |-------------------------------------------------------------------------- 50 | | Scroll Behavior 51 | |-------------------------------------------------------------------------- 52 | | 53 | | Allows for a customized global scrolling function 54 | | 55 | */ 56 | 57 | scrollBehavior: null, 58 | 59 | /* 60 | |-------------------------------------------------------------------------- 61 | | Query Parser 62 | |-------------------------------------------------------------------------- 63 | | 64 | | Provide custom query string parser. 65 | | 66 | */ 67 | 68 | parseQuery: null, 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Stringify function 73 | |-------------------------------------------------------------------------- 74 | | 75 | | Provide custom query stringify function. 76 | | 77 | */ 78 | 79 | stringifyQuery: null, 80 | 81 | /* 82 | |-------------------------------------------------------------------------- 83 | | Fallback links 84 | |-------------------------------------------------------------------------- 85 | | 86 | | Controls whether the router should fallback to hash mode when the 87 | | browser does not support history.pushState. Defaults to true. 88 | | 89 | */ 90 | 91 | fallback: true, 92 | }; 93 | -------------------------------------------------------------------------------- /src/state/StateServiceInterface.ts: -------------------------------------------------------------------------------- 1 | export default interface StateServiceInterface { 2 | getStore(): any; 3 | registerStore(store: any): StateServiceInterface; 4 | } 5 | -------------------------------------------------------------------------------- /src/state/StateServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import VuexService from "./VuexService"; 2 | import ServiceProvider from "../support/ServiceProvider"; 3 | import StateServiceInterface from "./StateServiceInterface"; 4 | 5 | export default class StateServiceProvider extends ServiceProvider { 6 | public $store; 7 | 8 | public boot() { 9 | this.$store = this.app.make("StateService"); 10 | 11 | // @ts-ignore 12 | if (typeof this.map === "function") { 13 | // @ts-ignore 14 | this.map(); 15 | } else { 16 | throw "Your state service provider must have a map function."; 17 | } 18 | } 19 | 20 | public register() { 21 | this.app.singleton("StateService", VuexService); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/state/StoreModule.ts: -------------------------------------------------------------------------------- 1 | import { Store } from "vuex"; 2 | type GenericObject = { [key: string]: any }; 3 | import { injectable, inject } from "inversify"; 4 | 5 | @injectable() 6 | export default class StoreModule { 7 | public name; 8 | public modules = {}; 9 | public namespaced = true; 10 | public state: GenericObject = {}; 11 | public actions: GenericObject = {}; 12 | public getters: GenericObject = {}; 13 | public mutations: GenericObject = {}; 14 | public $modules: Array = []; 15 | 16 | setName(name) { 17 | this.name = name; 18 | return this; 19 | } 20 | 21 | addState(state) { 22 | this.state = Object.assign({}, this.state, state); 23 | return this; 24 | } 25 | 26 | addActions(actions) { 27 | if (typeof actions === "function") { 28 | actions = actions(); 29 | } 30 | this.actions = Object.assign({}, this.actions, actions); 31 | return this; 32 | } 33 | 34 | addMutations(mutations) { 35 | if (typeof mutations === "function") { 36 | mutations = mutations(); 37 | } 38 | this.mutations = Object.assign({}, this.mutations, mutations); 39 | return this; 40 | } 41 | 42 | addGetters(getters) { 43 | if (typeof getters === "function") { 44 | getters = getters(); 45 | } 46 | this.getters = Object.assign({}, this.getters, getters); 47 | return this; 48 | } 49 | 50 | addModule(store) { 51 | this.$modules.push(store); 52 | return this; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/state/VuexService.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex, { Store } from "vuex"; 3 | import StoreModule from "./StoreModule"; 4 | import camelize from "../utilities/camelize"; 5 | import { inject, injectable } from "inversify"; 6 | import StateServiceInterface from "./StateServiceInterface"; 7 | import ApplicationInterface from "../foundation/ApplicationInterface"; 8 | 9 | @injectable() 10 | export default class VuexService implements StateServiceInterface { 11 | protected store: Store; 12 | protected app: ApplicationInterface; 13 | 14 | constructor(@inject("app") app: ApplicationInterface) { 15 | Vue.use(Vuex); 16 | this.app = app; 17 | this.store = new Vuex.Store({}); 18 | this.store.registerModule("varie", { 19 | namespaced: true, 20 | state: {}, 21 | }); 22 | } 23 | 24 | public getStore(): Store { 25 | return this.store; 26 | } 27 | 28 | public registerStore(Store: StoreModule) { 29 | let store = this.bindStore(Store); 30 | this.store.registerModule( 31 | this.getStoreName(store), 32 | this.registerSubModules(store), 33 | ); 34 | return this; 35 | } 36 | 37 | protected registerSubModules(store: StoreModule) { 38 | store.$modules.forEach((Module) => { 39 | let module = this.bindStore(Module); 40 | store.modules[this.getStoreName(module)] = this.registerSubModules( 41 | module, 42 | ); 43 | }); 44 | return store; 45 | } 46 | 47 | protected getStoreName(store: StoreModule) { 48 | if (!store.name) { 49 | throw "Your store does not have a name"; 50 | } 51 | return store.name; 52 | } 53 | 54 | protected bindStore(Store: StoreModule) { 55 | let moduleAbstractName = camelize(`store ${Store.name}`); 56 | this.app.singleton(moduleAbstractName, Store); 57 | return this.app.make(moduleAbstractName); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/storage/StorageService.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from "inversify"; 2 | import StorageServiceInterface from "./StorageServiceInterface"; 3 | 4 | @injectable() 5 | export default class StorageService implements StorageServiceInterface { 6 | public get(key: string): any { 7 | return localStorage.getItem(key); 8 | } 9 | 10 | public set(key: string, value: any): void { 11 | localStorage.setItem(key, value); 12 | } 13 | 14 | public remove(key): void { 15 | localStorage.removeItem(key); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/storage/StorageServiceInterface.ts: -------------------------------------------------------------------------------- 1 | export default interface StorageServiceInterface { 2 | get(key: string): any; 3 | set(key: string, value: any): void; 4 | remove(key: string): void; 5 | } 6 | -------------------------------------------------------------------------------- /src/storage/StorageServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import StorageService from "./StorageService"; 2 | import ServiceProvider from "../support/ServiceProvider"; 3 | import StorageServiceInterface from "./StorageServiceInterface"; 4 | 5 | export default class StorageServiceProvider extends ServiceProvider { 6 | public register() { 7 | this.app.singleton( 8 | "StorageService", 9 | StorageService, 10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/support/Model.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | 3 | export default class Model { 4 | constructor(data: object) { 5 | this.defaults(); 6 | Object.assign(this, data); 7 | } 8 | 9 | protected defaults() { 10 | // ... 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/support/ServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from "inversify"; 2 | import ConfigInterface from "../config/ConfigInterface"; 3 | import ServiceProviderInterface from "./ServiceProviderInterface"; 4 | import ApplicationInterface from "./../foundation/ApplicationInterface"; 5 | 6 | @injectable() 7 | export default class ServiceProvider implements ServiceProviderInterface { 8 | public app: ApplicationInterface; 9 | 10 | constructor(app: ApplicationInterface) { 11 | this.app = app; 12 | this.app.addProvider(this); 13 | } 14 | 15 | protected mergeConfigFrom(frameworkConfig: any, key: string) { 16 | let appConfig = this.app.make("ConfigService").get(key); 17 | 18 | for (let appConfigKey in appConfig) { 19 | if (appConfig[appConfigKey] !== undefined) { 20 | if ( 21 | frameworkConfig[appConfigKey] instanceof Object && 22 | appConfig[appConfigKey] instanceof Object 23 | ) { 24 | Object.assign(frameworkConfig[appConfigKey], appConfig[appConfigKey]); 25 | } else { 26 | frameworkConfig[appConfigKey] = appConfig[appConfigKey]; 27 | } 28 | } 29 | } 30 | $config.set(key, frameworkConfig); 31 | } 32 | 33 | public boot() {} 34 | } 35 | -------------------------------------------------------------------------------- /src/support/ServiceProviderInterface.ts: -------------------------------------------------------------------------------- 1 | export default interface ServiceProviderInterface { 2 | boot(): any; 3 | register?(): any; 4 | } 5 | -------------------------------------------------------------------------------- /src/utilities/camelize.ts: -------------------------------------------------------------------------------- 1 | import camelCase from "camelcase"; 2 | 3 | export default function(data: string) { 4 | return camelCase(data); 5 | } 6 | -------------------------------------------------------------------------------- /src/utilities/clone.ts: -------------------------------------------------------------------------------- 1 | import * as cloneDeep from "clone-deep"; 2 | 3 | export default function(data: object) { 4 | return cloneDeep(data); 5 | } 6 | -------------------------------------------------------------------------------- /src/utilities/dashify.ts: -------------------------------------------------------------------------------- 1 | import * as dashify from "dashify"; 2 | 3 | export default function(string: string) { 4 | return dashify(string); 5 | } 6 | -------------------------------------------------------------------------------- /src/utilities/filterEmpty.ts: -------------------------------------------------------------------------------- 1 | export default function(data: object) { 2 | for (let propName in data) { 3 | if (data[propName] === null || data[propName] === undefined) { 4 | delete data[propName]; 5 | } 6 | } 7 | return data; 8 | } 9 | -------------------------------------------------------------------------------- /src/utilities/getByDot.ts: -------------------------------------------------------------------------------- 1 | export default function(data: object, path: string, defaultValue?: any) { 2 | let value = path.split(".").reduce(function(prev: object, curr: string) { 3 | return prev ? prev[curr] : undefined; 4 | }, data); 5 | 6 | return value !== undefined ? value : defaultValue; 7 | } 8 | -------------------------------------------------------------------------------- /src/utilities/index.ts: -------------------------------------------------------------------------------- 1 | import camelize from "./camelize"; 2 | import clone from "./clone"; 3 | import dashify from "./dashify"; 4 | import filterEmpty from "./filterEmpty"; 5 | import getByDot from "./getByDot"; 6 | import isEmpty from "./isEmpty"; 7 | import setByDot from "./setByDot"; 8 | import uncamelize from "./uncamelize"; 9 | 10 | export { 11 | camelize, 12 | clone, 13 | dashify, 14 | filterEmpty, 15 | getByDot, 16 | isEmpty, 17 | setByDot, 18 | uncamelize, 19 | }; 20 | -------------------------------------------------------------------------------- /src/utilities/isEmpty.ts: -------------------------------------------------------------------------------- 1 | export default function(value: object | string | null | Array) { 2 | //check for empty object {}, array [] 3 | if (value !== null && typeof value === "object") { 4 | if (Object.keys(value).length === 0) { 5 | return true; 6 | } 7 | } else if ( 8 | value == null || 9 | (typeof value === "string" && value.replace(/\s+/, "") === "") 10 | ) { 11 | //check for undefined, null and "" 12 | return true; 13 | } 14 | 15 | return false; 16 | } 17 | -------------------------------------------------------------------------------- /src/utilities/setByDot.ts: -------------------------------------------------------------------------------- 1 | export default function(data: object, path: string, value: any) { 2 | let parts = path.split("."); 3 | return parts.reduce(function(prev: object, curr: string, ix: number) { 4 | return ix + 1 == parts.length ? (prev[curr] = value) : prev[curr] || {}; 5 | }, data); 6 | } 7 | -------------------------------------------------------------------------------- /src/utilities/uncamelize.ts: -------------------------------------------------------------------------------- 1 | export default function(string: string) { 2 | return string 3 | .replace(/([a-z])([A-Z])/g, "$1 $2") 4 | .replace(/\b([A-Z]+)([A-Z])([a-z])/, "$1 $2$3") 5 | .toLowerCase(); 6 | } 7 | -------------------------------------------------------------------------------- /src/validation/Validation.ts: -------------------------------------------------------------------------------- 1 | import isNumeric from "validator/lib/isNumeric"; 2 | import { getByDot, uncamelize } from "./../utilities"; 3 | import ConfigInterface from "../config/ConfigInterface"; 4 | 5 | export default class Validation { 6 | public errors: object = {}; 7 | 8 | protected data: object; 9 | protected configService; 10 | protected schema: object; 11 | protected messages: object; 12 | protected rules: object = {}; 13 | 14 | /** 15 | * The size related validation rules. 16 | * 17 | * @var array 18 | */ 19 | protected sizeRules = ["between", "min", "max", "size"]; 20 | 21 | constructor( 22 | data: object, 23 | schema: object, 24 | messages: object, 25 | configService: ConfigInterface, 26 | ) { 27 | this.data = data; 28 | this.schema = schema; 29 | this.messages = messages; 30 | this.configService = configService; 31 | this.rules = this.configService.get("validation.rules"); 32 | } 33 | 34 | public validate() { 35 | return this.validateSchema(this.schema); 36 | } 37 | 38 | protected validateSchema(schema: any, key?: string) { 39 | for (let field in schema) { 40 | if (typeof schema[field] === "object") { 41 | this.validateSchema(schema[field], key ? `${key}.${field}` : field); 42 | } else { 43 | let ruleField = key ? `${key}.${field}` : field; 44 | this.checkRules(ruleField, schema[field]); 45 | } 46 | } 47 | return this.errors; 48 | } 49 | 50 | protected checkRules(field: string, rules: string) { 51 | let rulesArray = rules.split("|"); 52 | if (rulesArray.length) { 53 | for (let ruleIndex in rulesArray) { 54 | let tempRule = rulesArray[ruleIndex].split(":"); 55 | let rule = tempRule[0]; 56 | let parameters: Array = []; 57 | if (tempRule[1]) { 58 | parameters = tempRule[1].split(","); 59 | } 60 | 61 | parameters = parameters.map((parameter) => { 62 | if (parameter === "false") { 63 | return false; 64 | } 65 | if (parameter === "true") { 66 | return true; 67 | } 68 | let number = parseFloat(parameter); 69 | if (!isNaN(number)) { 70 | return number; 71 | } 72 | return parameter; 73 | }); 74 | 75 | let ruleClass = this.getRule(rule); 76 | if (ruleClass === undefined) { 77 | throw `We cannot find the rule ${rule}`; 78 | } 79 | 80 | if ( 81 | !ruleClass.passes( 82 | this.getValue(field), 83 | parameters, 84 | this.data, 85 | field, 86 | ) && 87 | rule !== "nullable" 88 | ) { 89 | this.errors[field] = this.makeReplacements( 90 | this.getMessage(rule, field), 91 | rule, 92 | field, 93 | parameters, 94 | ); 95 | break; 96 | } 97 | 98 | if (rule === "nullable") { 99 | break; 100 | } 101 | } 102 | } 103 | } 104 | 105 | protected getRule(rule: string) { 106 | return this.rules[rule]; 107 | } 108 | 109 | protected makeReplacements( 110 | message: string, 111 | rule: string, 112 | field: string, 113 | parameters: any, 114 | ) { 115 | let ruleFunctions = this.getRule(rule); 116 | if (!message) { 117 | return `The ${field} fails the validation.`; 118 | } 119 | message = message.replace(":field", uncamelize(field.replace(".", "s "))); 120 | if (ruleFunctions.replacers) { 121 | ruleFunctions.replacers().forEach((replacer: string, index: number) => { 122 | if (parameters[index]) { 123 | message = message.replace( 124 | `:${replacer}`, 125 | typeof parameters[index] === "string" 126 | ? uncamelize( 127 | parameters[index].replace("_", " ").replace(".", "s "), 128 | ) 129 | : parameters[index], 130 | ); 131 | } 132 | }); 133 | } 134 | 135 | if (message.indexOf(":values") > -1) { 136 | message.replace(":values", parameters.join(", ")); 137 | } 138 | 139 | return message; 140 | } 141 | 142 | protected getValue(field: string) { 143 | return getByDot(this.data, field); 144 | } 145 | 146 | protected getMessage(rule: string, field: string) { 147 | let customMessage = getByDot(this.messages, field); 148 | 149 | if (customMessage) { 150 | return customMessage; 151 | } 152 | 153 | if (this.sizeRules.indexOf(rule) > -1) { 154 | return this.getSizeMessage(field, rule); 155 | } 156 | 157 | let tempRule = this.getRule(rule).message; 158 | if (tempRule) { 159 | return tempRule(); 160 | } 161 | 162 | return this.getMessageFromLocale(rule); 163 | } 164 | 165 | protected getSizeMessage(field: string, rule: string) { 166 | let type = "string"; 167 | let locale = this.configService.get("app.locale"); 168 | let value = getByDot(this.data, field); 169 | 170 | if (typeof value === "object") { 171 | type = "file"; 172 | } else if (Array.isArray(value)) { 173 | type = "array"; 174 | } else if (isNumeric(value)) { 175 | type = "numeric"; 176 | } 177 | 178 | return this.configService.get(`validation.${locale}.${rule}.${type}`); 179 | } 180 | 181 | protected getMessageFromLocale(rule: string) { 182 | let locale = this.configService.get("app.locale"); 183 | return this.configService.get(`validation.${locale}.${rule}`); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/validation/ValidationServiceInterface.ts: -------------------------------------------------------------------------------- 1 | export default interface ValidationServiceInterface {} 2 | -------------------------------------------------------------------------------- /src/validation/ValidationServiceProvider.ts: -------------------------------------------------------------------------------- 1 | import ValidationConfig from "./config"; 2 | import ServiceProvider from "../support/ServiceProvider"; 3 | import VarieValidationService from "./VarieValidationService"; 4 | import ValidationServiceInterface from "./ValidationServiceInterface"; 5 | 6 | export default class ValidationServiceProvider extends ServiceProvider { 7 | public boot() { 8 | require("./directive/Validate"); 9 | } 10 | 11 | public register() { 12 | this.mergeConfigFrom(ValidationConfig, "validation"); 13 | 14 | let files = require.context("@resources/lang", true, /validation\.(ts)$/); 15 | 16 | for (let filename of files.keys()) { 17 | $config.set( 18 | `validation.${filename 19 | .replace("./", "") 20 | .split("/") 21 | .shift()}`, 22 | files(filename).default, 23 | ); 24 | } 25 | 26 | this.app.singleton( 27 | "ValidationService", 28 | VarieValidationService, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/validation/Validator.ts: -------------------------------------------------------------------------------- 1 | import Form from "../plugins/forms/Form"; 2 | import { inject, injectable } from "inversify"; 3 | import ValidationServiceInterface from "./ValidationServiceInterface"; 4 | 5 | @injectable() 6 | export default class Validator extends Form { 7 | public rules = {}; 8 | public messages = {}; 9 | 10 | // TODO - should re-think how this validator is used , not a fan of how I thought of it the first time 11 | constructor( 12 | @inject("ValidationService") validationService: ValidationServiceInterface, 13 | ) { 14 | super({}, validationService); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/validation/VarieValidationService.ts: -------------------------------------------------------------------------------- 1 | import Validation from "./Validation"; 2 | import { injectable, inject } from "inversify"; 3 | import ValidationServiceInterface from "./ValidationServiceInterface"; 4 | 5 | @injectable() 6 | export default class ValidationService implements ValidationServiceInterface { 7 | protected configService; 8 | 9 | constructor(@inject("ConfigService") configService) { 10 | this.configService = configService; 11 | } 12 | 13 | public validate(data: object, schema: object, messages = {}) { 14 | return new Validation( 15 | data, 16 | schema, 17 | messages, 18 | this.configService, 19 | ).validate(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/validation/config.ts: -------------------------------------------------------------------------------- 1 | import Rules from "./rules"; 2 | 3 | export default { 4 | /* 5 | |-------------------------------------------------------------------------- 6 | | Custom Rules 7 | |-------------------------------------------------------------------------- 8 | | 9 | | You can supply your custom rules here 10 | | 11 | */ 12 | 13 | rules: Rules, 14 | }; 15 | -------------------------------------------------------------------------------- /src/validation/directive/Validate.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Form from "../../plugins/forms/Form"; 3 | 4 | function checkForErrors(formElement, form: Form) { 5 | let errors = form.errors(); 6 | formElement.querySelectorAll("*[validate]").forEach((el) => { 7 | if (el.hasAttribute("touched") && errors[el.name]) { 8 | return attachError(el, errors[el.name]); 9 | } 10 | removeErrors(el); 11 | }); 12 | } 13 | 14 | function attachError(el: HTMLInputElement, error) { 15 | let validationElement = getValidationErrorElement(el); 16 | if (!validationElement) { 17 | el.insertAdjacentHTML( 18 | "afterend", 19 | `
${error}
`, 20 | ); 21 | } else { 22 | // @ts-ignore 23 | validationElement.innerHTML = error; 24 | } 25 | } 26 | 27 | function removeErrors(el: HTMLInputElement) { 28 | let validationElement = getValidationErrorElement(el); 29 | if (validationElement) { 30 | // @ts-ignore 31 | validationElement.remove(); 32 | } 33 | } 34 | 35 | function getValidationErrorElement( 36 | el: HTMLInputElement, 37 | ): HTMLInputElement | boolean { 38 | let sibling = el.nextSibling; 39 | // @ts-ignore 40 | if (sibling && sibling.classList) { 41 | // @ts-ignore 42 | return sibling.classList.contains("validation-error") && sibling; 43 | } 44 | return false; 45 | } 46 | 47 | // @ts-ignore 48 | Vue.directive("form", { 49 | inserted(formElement: HTMLInputElement, vNode) { 50 | // @ts-ignore 51 | formElement 52 | .querySelectorAll("*[validate]") 53 | // @ts-ignore 54 | .forEach((el: HTMLInputElement) => { 55 | switch (el.type) { 56 | case "radio": 57 | case "checkbox": 58 | el.onchange = () => { 59 | el.setAttribute("touched", "true"); 60 | checkForErrors(formElement, vNode.value); 61 | }; 62 | break; 63 | default: 64 | el.oninput = () => { 65 | checkForErrors(formElement, vNode.value); 66 | el.onblur = () => { 67 | el.setAttribute("touched", "true"); 68 | checkForErrors(formElement, vNode.value); 69 | }; 70 | }; 71 | break; 72 | } 73 | }); 74 | }, 75 | }); 76 | -------------------------------------------------------------------------------- /src/validation/rules/accepted.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: any) { 3 | let validValues = ["yes", "on", 1, true]; 4 | 5 | return validValues.indexOf(value) > -1; 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/validation/rules/after.ts: -------------------------------------------------------------------------------- 1 | import isDate from "./date"; 2 | import isAfter from "validator/lib/isAfter"; 3 | 4 | export default { 5 | passes(value: any, parameters: Array) { 6 | if (value && isDate.passes(value)) { 7 | return isAfter(value, parameters[0]); 8 | } 9 | return false; 10 | }, 11 | 12 | replacers() { 13 | return ["date"]; 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/validation/rules/after_or_equal.ts: -------------------------------------------------------------------------------- 1 | import isDate from "./date"; 2 | import isAfter from "validator/lib/isAfter"; 3 | import isBefore from "validator/lib/isBefore"; 4 | 5 | export default { 6 | passes(value: any, parameters: Array) { 7 | if (value && isDate.passes(value)) { 8 | return ( 9 | isAfter(value, parameters[0]) || 10 | (!isAfter(value, parameters[0]) && !isBefore(value, parameters[0])) 11 | ); 12 | } 13 | return false; 14 | }, 15 | 16 | replacers() { 17 | return ["date"]; 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /src/validation/rules/alpha.ts: -------------------------------------------------------------------------------- 1 | import isAlpha from "validator/lib/isAlpha"; 2 | 3 | export default { 4 | passes(value: any) { 5 | return isAlpha(value); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/validation/rules/alpha_num.ts: -------------------------------------------------------------------------------- 1 | import isAlphanumeric from "validator/lib/isAlphanumeric"; 2 | 3 | export default { 4 | passes(value: any) { 5 | return isAlphanumeric(value); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/validation/rules/array.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: any) { 3 | return Array.isArray(value); 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /src/validation/rules/before.ts: -------------------------------------------------------------------------------- 1 | import isDate from "./date"; 2 | import isBefore from "validator/lib/isBefore"; 3 | 4 | export default { 5 | passes(value: any, parameters: Array) { 6 | if (value && isDate.passes(value)) { 7 | return isBefore(value, parameters[0]); 8 | } 9 | return false; 10 | }, 11 | 12 | replacers() { 13 | return ["date"]; 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/validation/rules/before_or_equal.ts: -------------------------------------------------------------------------------- 1 | import isDate from "./date"; 2 | import isAfter from "validator/lib/isAfter"; 3 | import isBefore from "validator/lib/isBefore"; 4 | 5 | export default { 6 | passes(value: any, parameters: Array) { 7 | if (value && isDate.passes(value)) { 8 | return ( 9 | isBefore(value, parameters[0]) || 10 | (!isAfter(value, parameters[0]) && !isBefore(value, parameters[0])) 11 | ); 12 | } 13 | return false; 14 | }, 15 | 16 | replacers() { 17 | return ["date"]; 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /src/validation/rules/between.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: { size: number }, parameters: Array) { 3 | if (value) { 4 | let min = parameters[0]; 5 | let max = parameters[1]; 6 | 7 | if (Array.isArray(value) || typeof value === "string") { 8 | return min <= value.length && max >= value.length; 9 | } else if (typeof value === "object") { 10 | return min <= value.size / 1024 && max >= value.size / 1024; 11 | } 12 | 13 | return min <= value && max >= value; 14 | } 15 | }, 16 | 17 | replacers() { 18 | return ["min", "max"]; 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /src/validation/rules/boolean.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: any) { 3 | return value === true || value === false || value === 0 || value === 1; 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /src/validation/rules/confirmed.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: any, parameters: Array, formData: object, currentField) { 3 | return formData[`${currentField}_confirmation`] === value; 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /src/validation/rules/date.ts: -------------------------------------------------------------------------------- 1 | import isISO8601 from "validator/lib/isISO8601"; 2 | import isRFC3339 from "validator/lib/isRFC3339"; 3 | 4 | export default { 5 | passes(value: any) { 6 | if (value) { 7 | return value instanceof Date || isISO8601(value) || isRFC3339(value); 8 | } 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /src/validation/rules/different.ts: -------------------------------------------------------------------------------- 1 | import { getByDot } from "./../../utilities"; 2 | 3 | export default { 4 | passes(value: any, parameters: Array, data: {}): boolean { 5 | return value !== getByDot(data, parameters[0]); 6 | }, 7 | 8 | replacers() { 9 | return ["other"]; 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /src/validation/rules/email.ts: -------------------------------------------------------------------------------- 1 | import isEmail from "validator/lib/isEmail"; 2 | 3 | export default { 4 | passes(value: any) { 5 | return isEmail(value); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/validation/rules/image.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(files: File | Array) { 3 | if (files) { 4 | if (!Array.isArray(files)) { 5 | files = [files]; 6 | } 7 | let validLength = 0; 8 | 9 | let fileTypeRegex = new RegExp(/(jpg|svg|jpeg|png|bmp|gif)$/i); 10 | let fileNameRegex = new RegExp(/\.(jpg|svg|jpeg|png|bmp|gif)$/i); 11 | 12 | files.forEach((file) => { 13 | if (fileNameRegex.test(file.name) || fileTypeRegex.test(file.type)) { 14 | validLength++; 15 | } 16 | }); 17 | 18 | return validLength === files.length; 19 | } 20 | 21 | return true; 22 | }, 23 | 24 | replacers() { 25 | return ["values"]; 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/validation/rules/index.ts: -------------------------------------------------------------------------------- 1 | import accepted from "./accepted"; 2 | import after from "./after"; 3 | import after_or_equal from "./after_or_equal"; 4 | import alpha from "./alpha"; 5 | import alpha_num from "./alpha_num"; 6 | import array from "./array"; 7 | import confirmed from "./confirmed"; 8 | import before from "./before"; 9 | import before_or_equal from "./before_or_equal"; 10 | import between from "./between"; 11 | import boolean from "./boolean"; 12 | import date from "./date"; 13 | import different from "./different"; 14 | import email from "./email"; 15 | import image from "./image"; 16 | import integer from "./integer"; 17 | import max from "./max"; 18 | import mimetypes from "./mimetypes"; 19 | import min from "./min"; 20 | import nullable from "./nullable"; 21 | import numeric from "./numeric"; 22 | import regex from "./regex"; 23 | import required from "./required"; 24 | import required_if from "./required_if"; 25 | import required_unless from "./required_unless"; 26 | import required_with from "./required_with"; 27 | import required_with_all from "./required_with_all"; 28 | import required_without from "./required_without"; 29 | import required_without_all from "./required_without_all"; 30 | import same from "./same"; 31 | import string from "./string"; 32 | import size from "./size"; 33 | import url from "./url"; 34 | 35 | export default { 36 | accepted, 37 | after, 38 | after_or_equal, 39 | alpha, 40 | alpha_num, 41 | array, 42 | before, 43 | before_or_equal, 44 | between, 45 | boolean, 46 | confirmed, 47 | date, 48 | different, 49 | email, 50 | image, 51 | integer, 52 | max, 53 | mimetypes, 54 | min, 55 | nullable, 56 | numeric, 57 | regex, 58 | required, 59 | required_if, 60 | required_unless, 61 | required_with, 62 | required_with_all, 63 | required_without, 64 | required_without_all, 65 | same, 66 | size, 67 | string, 68 | url, 69 | }; 70 | -------------------------------------------------------------------------------- /src/validation/rules/integer.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: any) { 3 | return Number.isInteger(value); 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /src/validation/rules/max.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: { size: number }, attributes: Array) { 3 | if (value) { 4 | let max = attributes[0]; 5 | 6 | if (Array.isArray(value) || typeof value === "string") { 7 | return value.length <= max; 8 | } else if (typeof value === "object") { 9 | return value.size / 1024 <= max; 10 | } 11 | 12 | return value <= max; 13 | } 14 | return true; 15 | }, 16 | 17 | replacers() { 18 | return ["max", "size"]; 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /src/validation/rules/mimetypes.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(files: File | Array, parameters: Array) { 3 | if (files) { 4 | if (!Array.isArray(files)) { 5 | files = [files]; 6 | } 7 | let validLength = 0; 8 | 9 | const regex = new RegExp( 10 | `${parameters.join("|").replace("*", ".+")}$`, 11 | "i", 12 | ); 13 | 14 | files.forEach((file) => { 15 | if (regex.test(file.type)) { 16 | validLength++; 17 | } 18 | }); 19 | 20 | return validLength === files.length; 21 | } 22 | 23 | return true; 24 | }, 25 | 26 | replacers() { 27 | return ["values"]; 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /src/validation/rules/min.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: { size: number }, attributes: Array) { 3 | if (value) { 4 | let min = attributes[0]; 5 | 6 | if (Array.isArray(value) || typeof value === "string") { 7 | return value.length >= min; 8 | } else if (typeof value === "object") { 9 | return value.size / 1024 >= min; 10 | } 11 | 12 | return value >= min; 13 | } 14 | return true; 15 | }, 16 | 17 | replacers() { 18 | return ["min"]; 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /src/validation/rules/nullable.ts: -------------------------------------------------------------------------------- 1 | import isEmpty from "../../utilities/isEmpty"; 2 | 3 | export default { 4 | passes(value: any) { 5 | return isEmpty(value); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/validation/rules/numeric.ts: -------------------------------------------------------------------------------- 1 | import isNumeric from "validator/lib/isNumeric"; 2 | 3 | export default { 4 | passes(value: any) { 5 | if (typeof value === "number") { 6 | return true; 7 | } 8 | return isNumeric(value); 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /src/validation/rules/regex.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: any, parameters: Array) { 3 | let regex = parameters[0]; 4 | 5 | if (regex instanceof RegExp) { 6 | return regex.test(value); 7 | } else if (typeof regex === "string") { 8 | return new RegExp(regex).test(String(value)); 9 | } 10 | 11 | return false; 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /src/validation/rules/required.ts: -------------------------------------------------------------------------------- 1 | import { isEmpty } from "./../../utilities"; 2 | 3 | export default { 4 | passes(value: any): boolean { 5 | return !isEmpty(value); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/validation/rules/required_if.ts: -------------------------------------------------------------------------------- 1 | import { getByDot, isEmpty } from "./../../utilities"; 2 | 3 | export default { 4 | passes(value: any, parameters, data: {}): boolean { 5 | if (isEmpty(value)) { 6 | let requiredValue = getByDot(data, parameters[0]); 7 | return ( 8 | isEmpty(requiredValue) || 9 | (!isEmpty(parameters[1]) && requiredValue !== parameters[1]) 10 | ); 11 | } 12 | return true; 13 | }, 14 | 15 | replacers() { 16 | return ["other", "value"]; 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /src/validation/rules/required_unless.ts: -------------------------------------------------------------------------------- 1 | import { getByDot, isEmpty } from "./../../utilities"; 2 | 3 | // required_unless 4 | export default { 5 | passes(value: any, parameters: Array, data: {}): boolean { 6 | if (isEmpty(value)) { 7 | return getByDot(data, parameters[0]) === value; 8 | } 9 | return true; 10 | }, 11 | 12 | replacers() { 13 | return ["other", "value"]; 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/validation/rules/required_with.ts: -------------------------------------------------------------------------------- 1 | import { getByDot } from "./../../utilities"; 2 | 3 | export default { 4 | passes(value: any, parameters: Array, data: {}): boolean { 5 | if (!value) { 6 | let required = false; 7 | parameters.forEach((parameter) => { 8 | let parameterValue = getByDot(data, parameter); 9 | if (required === true || parameterValue) { 10 | required = true; 11 | } 12 | }); 13 | return !required; 14 | } 15 | return true; 16 | }, 17 | 18 | replacers() { 19 | return ["values"]; 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /src/validation/rules/required_with_all.ts: -------------------------------------------------------------------------------- 1 | import { getByDot } from "./../../utilities"; 2 | 3 | export default { 4 | passes(value: any, parameters: Array, data: {}): boolean { 5 | if (!value) { 6 | let validLength = 0; 7 | parameters.forEach((parameter) => { 8 | let parameterValue = getByDot(data, parameter); 9 | if (parameterValue) { 10 | validLength++; 11 | } 12 | }); 13 | if (validLength === parameters.length) { 14 | return false; 15 | } 16 | } 17 | return true; 18 | }, 19 | 20 | replacers() { 21 | return ["values"]; 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/validation/rules/required_without.ts: -------------------------------------------------------------------------------- 1 | import { getByDot } from "./../../utilities"; 2 | 3 | export default { 4 | passes(value: any, parameters: Array, data: {}): boolean { 5 | if (!value) { 6 | let required = true; 7 | parameters.forEach((parameter) => { 8 | let parameterValue = getByDot(data, parameter); 9 | if (required === false || !parameterValue) { 10 | required = false; 11 | } 12 | }); 13 | 14 | return required; 15 | } 16 | return true; 17 | }, 18 | 19 | replacers() { 20 | return ["values"]; 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/validation/rules/required_without_all.ts: -------------------------------------------------------------------------------- 1 | import { getByDot } from "./../../utilities"; 2 | 3 | export default { 4 | passes(value: any, parameters: Array, data: {}): boolean { 5 | if (!value) { 6 | let validLength = 0; 7 | parameters.forEach((parameter) => { 8 | let parameterValue = getByDot(data, parameter); 9 | if (parameterValue) { 10 | validLength++; 11 | } 12 | }); 13 | if (validLength === 0) { 14 | return false; 15 | } 16 | } 17 | return true; 18 | }, 19 | replacers() { 20 | return ["values"]; 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/validation/rules/same.ts: -------------------------------------------------------------------------------- 1 | import { getByDot } from "./../../utilities"; 2 | 3 | export default { 4 | passes(value: any, parameters: Array, data: {}): boolean { 5 | return value === getByDot(data, parameters[0]); 6 | }, 7 | 8 | replacers() { 9 | return ["other"]; 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /src/validation/rules/size.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: { size: number }, attributes: Array) { 3 | if (value) { 4 | let size = attributes[0]; 5 | 6 | if (Array.isArray(value) || typeof value === "string") { 7 | return value.length === size; 8 | } else if (typeof value === "object") { 9 | return value.size / 1024 === size; 10 | } 11 | 12 | return value === size; 13 | } 14 | return true; 15 | }, 16 | 17 | replacers() { 18 | return ["max", "size"]; 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /src/validation/rules/string.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: any): boolean { 3 | return typeof value === "string"; 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /src/validation/rules/url.ts: -------------------------------------------------------------------------------- 1 | import isURL from "validator/lib/isURL"; 2 | 3 | export default { 4 | passes(value: any): boolean { 5 | return isURL(value); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/vue-component.d.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | 3 | declare module "vue/types/options" { 4 | interface ComponentOptions { 5 | $inject?: Array; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /stubs/appMiddleware.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from "inversify"; 2 | import { AxiosRequestConfig, AxiosResponse, AxiosError } from "axios"; 3 | import HttpMiddlewareInterface from "varie/lib/http/interfaces/HttpMiddlewareInterface"; 4 | 5 | @injectable() 6 | export default class temp implements HttpMiddlewareInterface { 7 | public request(config: AxiosRequestConfig) { 8 | return config; 9 | } 10 | 11 | public response(response: AxiosResponse) { 12 | return response; 13 | } 14 | 15 | public responseError(error: AxiosError) { 16 | return error; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /stubs/component.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /stubs/directive.ts: -------------------------------------------------------------------------------- 1 | // https://vuejs.org/v2/guide/custom-directive.html 2 | import Vue from "vue"; 3 | 4 | Vue.directive("temp", { 5 | inserted: function(el, binding) { 6 | // ... 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /stubs/filter.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | 3 | Vue.filter("temp", (value) => { 4 | return value; 5 | }); 6 | -------------------------------------------------------------------------------- /stubs/mixin.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | 3 | Vue.mixin({ 4 | methods: { 5 | // 6 | }, 7 | computed: { 8 | // 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /stubs/model.ts: -------------------------------------------------------------------------------- 1 | import Model from "varie/lib/support/Model"; 2 | 3 | export default class tempModel extends Model { 4 | protected defaults() { 5 | // ... 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /stubs/provider.ts: -------------------------------------------------------------------------------- 1 | import ServiceProvider from "varie/lib/support/ServiceProvider"; 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | App Service Provider 6 | |-------------------------------------------------------------------------- 7 | | You can bind various items to the app here, or can create other 8 | | custom providers that bind the container 9 | | 10 | */ 11 | export default class tempProvider extends ServiceProvider { 12 | public async boot() { 13 | // ... 14 | } 15 | 16 | public async register() { 17 | // ... 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /stubs/routeMiddleware.ts: -------------------------------------------------------------------------------- 1 | import { Route, Location } from "vue-router"; 2 | import { injectable, inject } from "inversify"; 3 | import RouteMiddlewareInterface from "varie/lib/routing/RouteMiddlewareInterface"; 4 | 5 | @injectable() 6 | export default class temp implements RouteMiddlewareInterface { 7 | handler(to: Route, from: Route, next: (route?: Location) => void) { 8 | next(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /stubs/rule.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | passes(value: any, parameters = [], data: {}) { 3 | return true; 4 | }, 5 | 6 | message() { 7 | return "This :field has this message to display"; 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /stubs/service.ts: -------------------------------------------------------------------------------- 1 | import { injectable, inject } from "inversify"; 2 | import ConfigInterface from "varie/lib/config/ConfigInterface"; 3 | 4 | @injectable() 5 | export default class BroadcastService { 6 | protected configService: ConfigInterface; 7 | 8 | constructor(@inject("ConfigService") configService) { 9 | this.configService = configService; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /stubs/store/actions.ts: -------------------------------------------------------------------------------- 1 | import { ActionContext } from "vuex"; 2 | import RootState from "@store/rootState"; 3 | import { tempState } from "./stateInterface"; 4 | 5 | export default function(httpService) { 6 | return { 7 | sampleAction: (context: ActionContext, data) => { 8 | return httpService.post("/some-url", { 9 | data, 10 | }); 11 | }, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /stubs/store/getters.ts: -------------------------------------------------------------------------------- 1 | import { tempState } from "./stateInterface"; 2 | 3 | export default function() { 4 | return { 5 | SAMPLE_GETTER: (state: tempState) => { 6 | return state; 7 | }, 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /stubs/store/index.ts: -------------------------------------------------------------------------------- 1 | import state from "./state"; 2 | import actions from "./actions"; 3 | import getters from "./getters"; 4 | import mutations from "./mutations"; 5 | import StoreModule from "varie/lib/state/StoreModule"; 6 | import { injectable, inject, unmanaged } from "inversify"; 7 | 8 | @injectable() 9 | export default class temp extends StoreModule { 10 | constructor(@inject("HttpService") httpService) { 11 | super(); 12 | this.setName("store_name") 13 | .addState(state) 14 | .addActions(actions(httpService)) 15 | .addMutations(mutations) 16 | .addGetters(getters); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /stubs/store/mutations.ts: -------------------------------------------------------------------------------- 1 | import { tempState } from "./stateInterface"; 2 | 3 | export default function() { 4 | return { 5 | SAMPLE_MUTATION: (state: tempState, data) => {}, 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /stubs/store/state.ts: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /stubs/store/stateInterface.ts: -------------------------------------------------------------------------------- 1 | export interface tempState {} 2 | -------------------------------------------------------------------------------- /stubs/validator.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from "inversify"; 2 | import Validator from "varie/lib/validation/Validator"; 3 | 4 | @injectable() 5 | export default class temp extends Validator { 6 | public rules = { 7 | // 8 | }; 9 | 10 | public messages = { 11 | // 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "outDir": "./lib/", 5 | "moduleResolution": "node", 6 | "lib": ["es6", "dom", "dom.iterable"], 7 | "target": "es5", 8 | "strict": true, 9 | "types": [ 10 | "vue", 11 | "vuex", 12 | "node", 13 | "validator", 14 | "vue-router", 15 | "webpack-env", 16 | "reflect-metadata" 17 | ], 18 | "declaration": true, 19 | "noImplicitAny": false, 20 | "inlineSourceMap": true, 21 | "emitDecoratorMetadata": true, 22 | "experimentalDecorators": true, 23 | "allowSyntheticDefaultImports": true 24 | }, 25 | "include": ["src/**/*"] 26 | } 27 | --------------------------------------------------------------------------------