diff --git a/.babelrc b/.babelrc index 3299dd4a..ddcdf7ac 100644 --- a/.babelrc +++ b/.babelrc @@ -1,7 +1,8 @@ { "presets": [ + "@babel/preset-env", "@babel/preset-react", - "@babel/preset-env" + "@babel/preset-typescript" ], "plugins": [ ["@babel/plugin-proposal-class-properties", { "loose" : true }] diff --git a/.eslintrc b/.eslintrc index c587354a..708b8706 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,4 +1,14 @@ { "parser": "babel-eslint", + "rules": { + "import/extensions": [".js", ".ts"] + }, + "settings": { + "import/resolver": { + "node": { + "extensions": [".js", ".ts"] + } + } + }, "extends": ["airbnb", "prettier"] } diff --git a/dist/interfaces.d.ts b/dist/interfaces.d.ts new file mode 100644 index 00000000..372b5e9d --- /dev/null +++ b/dist/interfaces.d.ts @@ -0,0 +1,5 @@ +export declare type IValue = any; +export declare type IValues = { + [key: string]: IValue; +}; +export declare type IValidationFunction = (values: IValues, value: IValue, extra?: any) => boolean; diff --git a/dist/validationRules.d.ts b/dist/validationRules.d.ts new file mode 100644 index 00000000..fe8162bf --- /dev/null +++ b/dist/validationRules.d.ts @@ -0,0 +1,5 @@ +import { IValidationFunction } from './interfaces'; +declare const validations: { + [key: string]: IValidationFunction; +}; +export default validations; diff --git a/package.json b/package.json index 264ec698..1e4a795a 100644 --- a/package.json +++ b/package.json @@ -42,21 +42,23 @@ "browser": "dist/formsy-react.umd.js", "main": "dist/formsy-react.cjs.js", "module": "dist/formsy-react.esm.js", + "types": "dist/formsy-react.d.ts", "scripts": { - "build": "npm run build:clean && npm run build:js", + "build": "npm run build:clean && npm run build:types && npm run build:js", "build:clean": "rm -r dist/* || true", "build:js": "rollup -c", + "build:types": "tsc --emitDeclarationOnly", "changelog": "auto-changelog", "deploy": "np", "format": "prettier --write \"**/*.{js,ts}\"", - "lint": "eslint src/**/*.js", + "lint": "eslint src/**/*", "preversion": "npm run lint", "test": "jest", "version": "npm run build && git add lib && git add release && npm run changelog && git add CHANGELOG.md" }, "dependencies": { "form-data-to-object": "^0.2.0", - "prop-types": "^15.5.10" + "prop-types": "^15.7.2" }, "devDependencies": { "@babel/cli": "^7.4.4", @@ -65,6 +67,8 @@ "@babel/plugin-proposal-class-properties": "^7.4.4", "@babel/preset-env": "^7.4.5", "@babel/preset-react": "^7.0.0", + "@babel/preset-typescript": "^7.3.3", + "@types/react": "^16.8.22", "auto-changelog": "^1.13.0", "babel-eslint": "^10.0.2", "babel-jest": "^24.8.0", @@ -75,7 +79,7 @@ "eslint": "^4.14.0", "eslint-config-airbnb": "^16.1.0", "eslint-config-prettier": "^5.0.0", - "eslint-plugin-import": "^2.7.0", + "eslint-plugin-import": "^2.17.3", "eslint-plugin-jsx-a11y": "^6.0.3", "eslint-plugin-react": "^7.5.1", "husky": "^2.4.1", @@ -90,7 +94,8 @@ "rollup-plugin-commonjs": "^10.0.0", "rollup-plugin-node-resolve": "^5.0.4", "rollup-plugin-peer-deps-external": "^2.2.0", - "sinon": "^7.3.2" + "sinon": "^7.3.2", + "typescript": "^3.5.2" }, "peerDependencies": { "react": "^15.6.1 || ^16.0.0", diff --git a/rollup.config.js b/rollup.config.js index 59d91c55..e9243c56 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -8,7 +8,7 @@ import pkg from './package.json'; const name = 'formsy-react', input = 'src/index.js', - extensions = ['.js'], + extensions = ['.js', '.ts'], babelConfig = { ...babelrc({ addExternalHelpersPlugin: false }), exclude: 'node_modules/**', diff --git a/src/interfaces.ts b/src/interfaces.ts new file mode 100644 index 00000000..11e8d634 --- /dev/null +++ b/src/interfaces.ts @@ -0,0 +1,3 @@ +export type IValue = any; +export type IValues = { [key: string]: IValue }; +export type IValidationFunction = (values: IValues, value: IValue, extra?: any) => boolean; diff --git a/src/validationRules.js b/src/validationRules.ts similarity index 56% rename from src/validationRules.js rename to src/validationRules.ts index 2c8e620f..4c72ae9a 100644 --- a/src/validationRules.js +++ b/src/validationRules.ts @@ -1,23 +1,25 @@ -const isExisty = value => value !== null && value !== undefined; -const isEmpty = value => value === ''; +import { IValidationFunction, IValue, IValues } from './interfaces'; -const validations = { - isDefaultRequiredValue(values, value) { +const isExisty = (value: IValue) => value !== null && value !== undefined; +const isEmpty = (value: IValue) => value === ''; + +const validations: { [key: string]: IValidationFunction } = { + isDefaultRequiredValue(_values: IValues, value: IValue) { return value === undefined || value === null || value === ''; }, - isExisty(_values, value) { + isExisty(_values: IValues, value: IValue) { return isExisty(value); }, - matchRegexp(_values, value, regexp) { + matchRegexp(_values: IValues, value: IValue, regexp: RegExp) { return !isExisty(value) || isEmpty(value) || regexp.test(value); }, - isUndefined(_values, value) { + isUndefined(_values: IValues, value: IValue) { return value === undefined; }, - isEmptyString(_values, value) { + isEmptyString(_values: IValues, value: IValue) { return isEmpty(value); }, - isEmail(values, value) { + isEmail(values: IValues, value: IValue) { // Regex from http://emailregex.com/ return validations.matchRegexp( values, @@ -25,52 +27,52 @@ const validations = { /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i, ); }, - isUrl(values, value) { + isUrl(values: IValues, value: IValue) { return validations.matchRegexp(values, value, /^(?:\w+:)?\/\/([^\s.]+\.\S{2}|localhost[:?\d]*)\S*$/i); }, - isTrue(_values, value) { + isTrue(_values: IValues, value: IValue) { return value === true; }, - isFalse(values, value) { + isFalse(_values: IValues, value: IValue) { return value === false; }, - isNumeric(values, value) { + isNumeric(values: IValues, value: IValue) { if (typeof value === 'number') { return true; } return validations.matchRegexp(values, value, /^[-+]?(?:\d*[.])?\d+$/); }, - isAlpha(values, value) { + isAlpha(values: IValues, value: IValue) { return validations.matchRegexp(values, value, /^[A-Z]+$/i); }, - isAlphanumeric(values, value) { + isAlphanumeric(values: IValues, value: IValue) { return validations.matchRegexp(values, value, /^[0-9A-Z]+$/i); }, - isInt(values, value) { + isInt(values: IValues, value: IValue) { return validations.matchRegexp(values, value, /^(?:[-+]?(?:0|[1-9]\d*))$/); }, - isFloat(values, value) { + isFloat(values: IValues, value: IValue) { return validations.matchRegexp(values, value, /^(?:[-+]?(?:\d+))?(?:\.\d*)?(?:[eE][+-]?(?:\d+))?$/); }, - isWords(values, value) { + isWords(values: IValues, value: IValue) { return validations.matchRegexp(values, value, /^[A-Z\s]+$/i); }, - isSpecialWords(values, value) { + isSpecialWords(values: IValues, value: IValue) { return validations.matchRegexp(values, value, /^[A-Z\s\u00C0-\u017F]+$/i); }, - isLength(_values, value, length) { + isLength(_values: IValues, value: IValue, length: number) { return !isExisty(value) || isEmpty(value) || value.length === length; }, - equals(_values, value, eql) { + equals(_values: IValues, value: IValue, eql: IValue) { return !isExisty(value) || isEmpty(value) || value === eql; }, - equalsField(values, value, field) { + equalsField(values: IValues, value: IValue, field: string) { return value === values[field]; }, - maxLength(_values, value, length) { + maxLength(_values: IValues, value: IValue, length: number) { return !isExisty(value) || value.length <= length; }, - minLength(_values, value, length) { + minLength(_values: IValues, value: IValue, length: number) { return !isExisty(value) || isEmpty(value) || value.length >= length; }, }; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..249a30d0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "declaration": true, + "lib": ["dom", "es5", "es6", "es7", "es2017.object"], + "outDir": "dist", + "sourceMap": true + }, + "exclude": ["node_modules", "dist", "coverage"], + "include": ["src"] +} diff --git a/yarn.lock b/yarn.lock index 25e0cdc9..9cb23130 100644 --- a/yarn.lock +++ b/yarn.lock @@ -352,6 +352,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-typescript@^7.2.0": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz#a7cc3f66119a9f7ebe2de5383cce193473d65991" + integrity sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-arrow-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" @@ -618,6 +625,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-typescript@^7.3.2": + version "7.4.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.4.5.tgz#ab3351ba35307b79981993536c93ff8be050ba28" + integrity sha512-RPB/YeGr4ZrFKNwfuQRlMf2lxoCUaU01MTw39/OFE/RiL8HDjtn68BwEPft1P7JN4akyEmjGWAMNldOV7o9V2g== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-typescript" "^7.2.0" + "@babel/plugin-transform-unicode-regex@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f" @@ -700,6 +715,14 @@ "@babel/plugin-transform-react-jsx-self" "^7.0.0" "@babel/plugin-transform-react-jsx-source" "^7.0.0" +"@babel/preset-typescript@^7.3.3": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz#88669911053fa16b2b276ea2ede2ca603b3f307a" + integrity sha512-mzMVuIP4lqtn4du2ynEfdO0+RYcslwrZiJHXu4MGaC1ctJiW2fyaeDrtjJGs7R/KebZ1sgowcIoWf4uRpEfKEg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.3.2" + "@babel/register@^7.0.0": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.4.4.tgz#370a68ba36f08f015a8b35d4864176c6b65d7a23" @@ -1038,6 +1061,19 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== +"@types/prop-types@*": + version "15.7.1" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6" + integrity sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg== + +"@types/react@^16.8.22": + version "16.8.22" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.22.tgz#7f18bf5ea0c1cad73c46b6b1c804a3ce0eec6d54" + integrity sha512-C3O1yVqk4sUXqWyx0wlys76eQfhrQhiDhDlHBrjER76lR2S2Agiid/KpOU9oCqj1dISStscz7xXz1Cg8+sCQeA== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + "@types/resolve@0.0.8": version "0.0.8" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" @@ -1879,6 +1915,7 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= content-type-parser@^1.0.1: version "1.0.2" @@ -1997,6 +2034,11 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": dependencies: cssom "0.3.x" +csstype@^2.2.0: + version "2.6.5" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.5.tgz#1cd1dff742ebf4d7c991470ae71e12bb6751e034" + integrity sha512-JsTaiksRsel5n7XwqPAfB0l3TFKdpjW/kgAELf9vrb5adGA7UCPLajKK5s3nFrcFm3Rkyp/Qkgl73ENc1UY3cA== + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -2172,6 +2214,7 @@ discontinuous-range@1.0.0: doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= dependencies: esutils "^2.0.2" isarray "^1.0.0" @@ -2410,7 +2453,7 @@ eslint-module-utils@^2.4.0: debug "^2.6.8" pkg-dir "^2.0.0" -eslint-plugin-import@^2.7.0: +eslint-plugin-import@^2.17.3: version "2.17.3" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.17.3.tgz#00548b4434c18faebaba04b24ae6198f280de189" integrity sha512-qeVf/UwXFJbeyLbxuY8RgqDyEKCkqV7YC+E5S5uOjAp4tOc8zj01JP3ucoBM8JcEqd1qRasJSg6LLlisirfy0Q== @@ -4310,6 +4353,7 @@ listr@^0.14.3: load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -5285,6 +5329,7 @@ path-to-regexp@^1.7.0: path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= dependencies: pify "^2.0.0" @@ -5450,7 +5495,7 @@ prop-types-exact@^1.2.0: object.assign "^4.1.0" reflect.ownkeys "^0.2.0" -prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -5557,6 +5602,7 @@ react-test-renderer@^16.0.0-0: read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= dependencies: find-up "^2.0.0" read-pkg "^2.0.0" @@ -5588,6 +5634,7 @@ read-pkg-up@^5.0.0: read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= dependencies: load-json-file "^2.0.0" normalize-package-data "^2.3.2" @@ -5867,14 +5914,14 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.7, resolve@^1.11.1, resolve@^1.3.2: +resolve@^1.1.7, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.3.2, resolve@^1.5.0: version "1.11.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== dependencies: path-parse "^1.0.6" -resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.0, resolve@^1.5.0: +resolve@^1.10.0, resolve@^1.10.1: version "1.11.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232" integrity sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw== @@ -6639,6 +6686,11 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +typescript@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.2.tgz#a09e1dc69bc9551cadf17dba10ee42cf55e5d56c" + integrity sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA== + uglify-js@^3.1.4: version "3.5.15" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.5.15.tgz#fe2b5378fd0b09e116864041437bff889105ce24"