Move to global eslint

Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
This commit is contained in:
John Molakvoæ (skjnldsv) 2019-09-26 17:51:44 +02:00
parent 713545f516
commit dd0a064868
No known key found for this signature in database
GPG Key ID: 60C25B8C072916CF
36 changed files with 1040 additions and 357 deletions

7
.babelrc.js Normal file
View File

@ -0,0 +1,7 @@
module.exports = {
plugins: [
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-proposal-object-rest-spread'
],
presets: ['@babel/preset-env']
}

View File

@ -1,101 +1,9 @@
module.exports = {
root: true,
env: {
browser: true,
es6: true,
node: true,
jest: true
},
globals: {
oc_config: true,
appVersion: true,
n: true,
t: true,
OC: true,
OCA: true,
Vue: true,
VueRouter: true
},
parserOptions: {
parser: 'babel-eslint',
ecmaVersion: 6
appVersion: true
},
extends: [
'eslint:recommended',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:node/recommended',
'plugin:vue/essential',
'plugin:vue/recommended',
'plugin:nextcloud/recommended',
'standard'
],
settings: {
'import/resolver': {
webpack: {
config: 'webpack.common.js'
},
node: {
paths: ['src'],
extensions: ['.js', '.vue']
}
}
},
plugins: ['vue', 'node'],
rules: {
// space before function ()
'space-before-function-paren': ['error', 'never'],
// curly braces always space
'object-curly-spacing': ['error', 'always'],
// stay consistent with array brackets
'array-bracket-newline': ['error', 'consistent'],
// 1tbs brace style
'brace-style': 'error',
// tabs only
indent: ['error', 'tab'],
'no-tabs': 0,
'vue/html-indent': ['error', 'tab'],
// only debug console
'no-console': ['error', { allow: ['error', 'warn', 'info', 'debug'] }],
// classes blocks
'padded-blocks': ['error', { classes: 'always' }],
// always have the operator in front
'operator-linebreak': ['error', 'before'],
// ternary on multiline
'multiline-ternary': ['error', 'always-multiline'],
// force proper JSDocs
'valid-jsdoc': [2, {
'prefer': {
'return': 'returns'
},
'requireReturn': false,
'requireReturnDescription': false
}],
// es6 import/export and require
'node/no-unpublished-require': ['off'],
'node/no-unsupported-features/es-syntax': ['off'],
// PascalCase components names for vuejs
// https://vuejs.org/v2/style-guide/#Single-file-component-filename-casing-strongly-recommended
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
// force name
'vue/match-component-file-name': ['error', {
'extensions': ['jsx', 'vue', 'js'],
'shouldMatchCase': true
}],
// space before self-closing elements
'vue/html-closing-bracket-spacing': 'error',
// no ending html tag on a new line
'vue/html-closing-bracket-newline': ['error', { multiline: 'never' }],
// code spacing with attributes
'vue/max-attributes-per-line': [
'error',
{
singleline: 3,
multiline: {
max: 3,
allowFirstLine: true
}
}
]
}
'nextcloud'
]
}

679
package-lock.json generated
View File

@ -1283,6 +1283,61 @@
"to-fast-properties": "^2.0.0"
}
},
"@nodelib/fs.scandir": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.2.tgz",
"integrity": "sha512-wrIBsjA5pl13f0RN4Zx4FNWmU71lv03meGKnqRUoCyan17s4V3WL92f3w3AIuWbNnpcrQyFBU5qMavJoB8d27w==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "2.0.2",
"run-parallel": "^1.1.9"
}
},
"@nodelib/fs.stat": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.2.tgz",
"integrity": "sha512-z8+wGWV2dgUhLqrtRYa03yDx4HWMvXKi1z8g3m2JyxAx8F7xk74asqPk5LAETjqDSGLFML/6CDl0+yFunSYicw==",
"dev": true
},
"@nodelib/fs.walk": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.3.tgz",
"integrity": "sha512-l6t8xEhfK9Sa4YO5mIRdau7XSOADfmh3jCr0evNHdY+HNkW6xuQhgMH7D73VV6WpZOagrW0UludvMTiifiwTfA==",
"dev": true,
"requires": {
"@nodelib/fs.scandir": "2.1.2",
"fastq": "^1.6.0"
}
},
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
"dev": true
},
"@types/glob": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
"integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
"dev": true,
"requires": {
"@types/events": "*",
"@types/minimatch": "*",
"@types/node": "*"
}
},
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
"integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
"dev": true
},
"@types/node": {
"version": "12.7.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.8.tgz",
"integrity": "sha512-FMdVn84tJJdV+xe+53sYiZS4R5yn1mAIxfj+DVoNiQjTYz1+OYmjwEZr1ev9nU0axXwda0QDbYl06QHanRVH3A==",
"dev": true
},
"@vue/component-compiler-utils": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.0.0.tgz",
@ -1566,9 +1621,9 @@
"dev": true
},
"abab": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz",
"integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz",
"integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg==",
"dev": true
},
"abbrev": {
@ -1584,9 +1639,9 @@
"dev": true
},
"acorn-globals": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz",
"integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==",
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz",
"integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==",
"dev": true,
"requires": {
"acorn": "^6.0.1",
@ -1600,9 +1655,9 @@
"dev": true
},
"acorn-walk": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
"integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==",
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==",
"dev": true
},
"ajv": {
@ -1847,9 +1902,9 @@
"dev": true
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
"dev": true
},
"asynckit": {
@ -2258,6 +2313,12 @@
}
}
},
"browserslist-config-nextcloud": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/browserslist-config-nextcloud/-/browserslist-config-nextcloud-0.0.1.tgz",
"integrity": "sha512-BUpPPPfE42jL2puSqfnsoOMoz6g+jqznoaoZmig4Kx1ULApBmM6iH+/7V1yblQz2PsOp39HET1byAB3h3h+kew==",
"dev": true
},
"buffer": {
"version": "4.9.1",
"resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
@ -2428,8 +2489,8 @@
"dev": true
},
"cdav-library": {
"version": "github:nextcloud/cdav-library#4f883682ecf74595938dd47fbce28e4072324f93",
"from": "github:nextcloud/cdav-library#4f883682ecf74595938dd47fbce28e4072324f93",
"version": "github:nextcloud/cdav-library#926a1b9e8c37a1a3337cfd1bf1254df044cde809",
"from": "github:nextcloud/cdav-library",
"requires": {
"@babel/polyfill": "^7.6.0"
},
@ -3108,15 +3169,15 @@
"dev": true
},
"cssom": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz",
"integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==",
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
"integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
"dev": true
},
"cssstyle": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz",
"integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz",
"integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==",
"dev": true,
"requires": {
"cssom": "0.3.x"
@ -3563,9 +3624,9 @@
"dev": true
},
"escodegen": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz",
"integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==",
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz",
"integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==",
"dev": true,
"requires": {
"esprima": "^3.1.3",
@ -3808,6 +3869,12 @@
}
}
},
"eslint-config-nextcloud": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/eslint-config-nextcloud/-/eslint-config-nextcloud-0.0.5.tgz",
"integrity": "sha512-innKCAJBpTTdEGriCQduV6XwDySdZ2uHD7PduaKbbSfL12a/eXU6/jcIDfxM3cFAgCN7sJYOSE4/TM9nygO8kQ==",
"dev": true
},
"eslint-config-standard": {
"version": "12.0.0",
"resolved": "http://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz",
@ -3984,13 +4051,21 @@
}
},
"eslint-plugin-es": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.4.1.tgz",
"integrity": "sha512-5fa/gR2yR3NxQf+UXkeLeP8FBBl6tSgdrAz1+cF84v1FMM4twGwQoqTnn+QxFLcPOrF4pdKEJKDB/q9GoyJrCA==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz",
"integrity": "sha512-f6fceVtg27BR02EYnBhgWLFQfK6bN4Ll0nQFrBHOlCsAyxeZkn0NHns5O0YZOPrV1B3ramd6cgFwaoFLcSkwEQ==",
"dev": true,
"requires": {
"eslint-utils": "^1.4.2",
"regexpp": "^2.0.1"
"regexpp": "^3.0.0"
},
"dependencies": {
"regexpp": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz",
"integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==",
"dev": true
}
}
},
"eslint-plugin-import": {
@ -4052,12 +4127,12 @@
}
},
"eslint-plugin-node": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-9.2.0.tgz",
"integrity": "sha512-2abNmzAH/JpxI4gEOwd6K8wZIodK3BmHbTxz4s79OIYwwIt2gkpEXlAouJXu4H1c9ySTnRso0tsuthSOZbUMlA==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz",
"integrity": "sha512-1CSyM/QCjs6PXaT18+zuAXsjXGIGo5Rw630rSKwokSs2jrYURQc4R5JZpoanNCqwNmepg+0eZ9L7YiRUJb8jiQ==",
"dev": true,
"requires": {
"eslint-plugin-es": "^1.4.1",
"eslint-plugin-es": "^2.0.0",
"eslint-utils": "^1.4.2",
"ignore": "^5.1.1",
"minimatch": "^3.0.4",
@ -4453,6 +4528,83 @@
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
"dev": true
},
"fast-glob": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.0.4.tgz",
"integrity": "sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.1",
"@nodelib/fs.walk": "^1.2.1",
"glob-parent": "^5.0.0",
"is-glob": "^4.0.1",
"merge2": "^1.2.3",
"micromatch": "^4.0.2"
},
"dependencies": {
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"glob-parent": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz",
"integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
},
"is-glob": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
"dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
"dev": true,
"requires": {
"braces": "^3.0.1",
"picomatch": "^2.0.5"
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
}
}
},
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
@ -4465,6 +4617,15 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
"fastq": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz",
"integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==",
"dev": true,
"requires": {
"reusify": "^1.0.0"
}
},
"fecha": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
@ -6452,9 +6613,9 @@
},
"dependencies": {
"acorn": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
"integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
"integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
"dev": true
}
}
@ -6950,6 +7111,12 @@
}
}
},
"merge2": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz",
"integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==",
"dev": true
},
"micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
@ -7227,6 +7394,406 @@
}
}
},
"mochapack": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/mochapack/-/mochapack-1.1.5.tgz",
"integrity": "sha512-k4Qukx7lpHLgvQcjCaJDa/PqvQED9DjsuuwaS2dTmjK2vus++DTYDRrnf4KYH2/aROgFqwPe+5gDhnAiwoxQ8Q==",
"dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"chalk": "^2.4.2",
"chokidar": "^3.0.2",
"glob-parent": "^5.0.0",
"globby": "^10.0.1",
"interpret": "^1.2.0",
"is-glob": "^4.0.1",
"loader-utils": "^1.2.3",
"lodash": "^4.17.15",
"memory-fs": "^0.4.1",
"minimatch": "^3.0.4",
"nodent-runtime": "^3.2.1",
"normalize-path": "^3.0.0",
"progress": "^2.0.3",
"source-map-support": "^0.5.13",
"strip-ansi": "^5.2.0",
"toposort": "^2.0.2",
"yargs": "^13.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"anymatch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.0.tgz",
"integrity": "sha512-Ozz7l4ixzI7Oxj2+cw+p0tVUt27BpaJ+1+q1TCeANWxHpvyn2+Un+YamBdfKu0uh8xLodGhoa1v7595NhKDAuA==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
}
},
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true
},
"big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
"dev": true
},
"binary-extensions": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
"integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
"dev": true
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"chokidar": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.1.1.tgz",
"integrity": "sha512-df4o16uZmMHzVQwECZRHwfguOt5ixpuQVaZHjYMvYisgKhE+JXwcj/Tcr3+3bu/XeOJQ9ycYmzu7Mv8XrGxJDQ==",
"dev": true,
"requires": {
"anymatch": "^3.1.0",
"braces": "^3.0.2",
"fsevents": "^2.0.6",
"glob-parent": "^5.0.0",
"is-binary-path": "^2.1.0",
"is-glob": "^4.0.1",
"normalize-path": "^3.0.0",
"readdirp": "^3.1.1"
}
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"dev": true,
"requires": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
}
},
"dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
"dev": true,
"requires": {
"path-type": "^4.0.0"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
"locate-path": "^3.0.0"
}
},
"fsevents": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz",
"integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==",
"dev": true,
"optional": true
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
"glob-parent": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz",
"integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
},
"globby": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz",
"integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==",
"dev": true,
"requires": {
"@types/glob": "^7.1.1",
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
"fast-glob": "^3.0.3",
"glob": "^7.1.3",
"ignore": "^5.1.1",
"merge2": "^1.2.3",
"slash": "^3.0.0"
}
},
"ignore": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
"integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==",
"dev": true
},
"interpret": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
"integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
"dev": true
},
"is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"requires": {
"binary-extensions": "^2.0.0"
}
},
"is-glob": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
"dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
"integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
"dev": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^2.0.0",
"json5": "^1.0.1"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
},
"memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
"integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
"dev": true,
"requires": {
"errno": "^0.1.3",
"readable-stream": "^2.0.1"
}
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"requires": {
"p-limit": "^2.0.0"
}
},
"path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
},
"readdirp": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.1.2.tgz",
"integrity": "sha512-8rhl0xs2cxfVsqzreYCvs8EwBfn/DhVdqtoLmw19uI3SC5avYX9teCurlErfpPXGmYtMHReGaP2RsLnFvz/lnw==",
"dev": true,
"requires": {
"picomatch": "^2.0.4"
}
},
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true
},
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-support": {
"version": "0.5.13",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
"integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"requires": {
"ansi-regex": "^4.1.0"
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
},
"toposort": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
"integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=",
"dev": true
},
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
}
},
"y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
},
"yargs": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
"integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
"dev": true,
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.1"
}
},
"yargs-parser": {
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
@ -8062,6 +8629,12 @@
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"dev": true
},
"picomatch": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz",
"integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==",
"dev": true
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
@ -9187,6 +9760,12 @@
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
"dev": true
},
"reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true
},
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
@ -9215,6 +9794,12 @@
"is-promise": "^2.1.0"
}
},
"run-parallel": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
"integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
"dev": true
},
"run-queue": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
@ -9457,12 +10042,12 @@
}
},
"saxes": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.9.tgz",
"integrity": "sha512-FZeKhJglhJHk7eWG5YM0z46VHmI3KJpMBAQm3xa9meDvd+wevB5GuBB0wc0exPInZiBBHqi00DbS8AcvCGCFMw==",
"version": "3.1.11",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz",
"integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==",
"dev": true,
"requires": {
"xmlchars": "^1.3.1"
"xmlchars": "^2.1.1"
}
},
"schema-utils": {
@ -10410,9 +10995,9 @@
"dev": true
},
"symbol-tree": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
"integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=",
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
"dev": true
},
"table": {
@ -12048,9 +12633,9 @@
}
},
"ws": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.0.0.tgz",
"integrity": "sha512-cknCal4k0EAOrh1SHHPPWWh4qm93g1IuGGGwBjWkXmCG7LsDtL8w9w+YVfaF+KSVwiHQKDIMsSLBVftKf9d1pg==",
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.1.2.tgz",
"integrity": "sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg==",
"dev": true,
"requires": {
"async-limiter": "^1.0.0"
@ -12069,9 +12654,9 @@
"dev": true
},
"xmlchars": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-1.3.1.tgz",
"integrity": "sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
},
"xtend": {

View File

@ -31,8 +31,8 @@
"lint:fix": "eslint --ext .js,.vue src tests --fix",
"stylelint": "stylelint src",
"stylelint:fix": "stylelint src --fix",
"test": "mocha-webpack --webpack-config webpack.test.js --interactive false --require tests/setup.js \"tests/js/**/*.spec.js\"",
"test:watch": "mocha-webpack -w --webpack-config webpack.test.js --interactive false --require tests/setup.js \"tests/js/**/*.spec.js\""
"test": "mochapack --webpack-config webpack.test.js --require tests/setup.js tests/unit/specs/**/*.spec.js",
"test:watch": "mochapack -w --webpack-config webpack.test.js --require tests/setup.js tests/unit/specs/**/*.spec.js"
},
"dependencies": {
"axios": "^0.19.0",
@ -59,10 +59,6 @@
"vuex": "^3.1.1",
"vuex-router-sync": "^5.0.0"
},
"browserslist": [
"last 2 versions",
"ie >= 11"
],
"engines": {
"node": ">=10.0.0"
},
@ -74,15 +70,17 @@
"@vue/test-utils": "^1.0.0-beta.29",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"browserslist-config-nextcloud": "0.0.1",
"chai": "^4.2.0",
"css-loader": "^3.2.0",
"eslint": "^5.16.0",
"eslint-config-nextcloud": "0.0.5",
"eslint-config-standard": "^12.0.0",
"eslint-import-resolver-webpack": "^0.11.1",
"eslint-loader": "^3.0.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-nextcloud": "^0.3.0",
"eslint-plugin-node": "^9.2.0",
"eslint-plugin-node": "^10.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-vue": "^5.2.3",
@ -91,6 +89,7 @@
"jsdom-global": "^3.0.2",
"mocha": "^5.2.0",
"mocha-webpack": "^2.0.0-beta.0",
"mochapack": "^1.1.5",
"node-sass": "^4.12.0",
"sass-loader": "^7.3.1",
"stylelint": "^8.4.0",
@ -104,5 +103,8 @@
"webpack-cli": "^3.3.9",
"webpack-merge": "^4.2.2",
"webpack-node-externals": "^1.7.2"
}
},
"browserslist": [
"extends browserslist-config-nextcloud"
]
}

View File

@ -27,7 +27,7 @@
</template>
<script>
import { ActionButton } from 'nextcloud-vue'
import ActionsMixin from 'Mixins/ActionsMixin'
import ActionsMixin from '../../mixins/ActionsMixin'
export default {
name: 'ActionCopyNtoFN',

View File

@ -22,13 +22,14 @@
<template>
<ActionCheckbox :checked="omitYear"
@check="removeYear" @uncheck="addYear">
@check="removeYear"
@uncheck="addYear">
{{ t('contacts', 'Omit year') }}
</ActionCheckbox>
</template>
<script>
import { ActionCheckbox } from 'nextcloud-vue'
import ActionsMixin from 'Mixins/ActionsMixin'
import ActionsMixin from '../../mixins/ActionsMixin'
export default {
name: 'ActionToggleYear',

View File

@ -46,20 +46,39 @@
<!-- fullname, org, title -->
<div id="contact-header-infos">
<h2>
<input id="contact-fullname" ref="fullname" v-model="contact.fullName"
:readonly="contact.addressbook.readOnly" :placeholder="t('contacts', 'Name')" type="text"
autocomplete="off" autocorrect="off" spellcheck="false"
<input id="contact-fullname"
ref="fullname"
v-model="contact.fullName"
:readonly="contact.addressbook.readOnly"
:placeholder="t('contacts', 'Name')"
type="text"
autocomplete="off"
autocorrect="off"
spellcheck="false"
name="fullname"
@input="debounceUpdateContact" @click="selectInput">
@input="debounceUpdateContact"
@click="selectInput">
</h2>
<div id="details-org-container">
<input id="contact-org" v-model="contact.org" :readonly="contact.addressbook.readOnly"
:placeholder="t('contacts', 'Company')" type="text" autocomplete="off"
autocorrect="off" spellcheck="false" name="org"
<input id="contact-org"
v-model="contact.org"
:readonly="contact.addressbook.readOnly"
:placeholder="t('contacts', 'Company')"
type="text"
autocomplete="off"
autocorrect="off"
spellcheck="false"
name="org"
@input="debounceUpdateContact">
<input id="contact-title" v-model="contact.title" :readonly="contact.addressbook.readOnly"
:placeholder="t('contacts', 'Title')" type="text" autocomplete="off"
autocorrect="off" spellcheck="false" name="title"
<input id="contact-title"
v-model="contact.title"
:readonly="contact.addressbook.readOnly"
:placeholder="t('contacts', 'Title')"
type="text"
autocomplete="off"
autocorrect="off"
spellcheck="false"
name="title"
@input="debounceUpdateContact">
</div>
</div>
@ -73,19 +92,24 @@
trigger: 'hover focus'
}"
:class="{'icon-loading-small': loadingUpdate,
[`${warning.icon}`]: warning}" class="header-icon" href="#" />
[`${warning.icon}`]: warning}"
class="header-icon"
href="#" />
<!-- conflict message -->
<div v-if="conflict" v-tooltip="{
<div v-if="conflict"
v-tooltip="{
content: conflict,
show: true,
trigger: 'manual',
}" class="header-icon header-icon--pulse icon-history-force-white"
}"
class="header-icon header-icon--pulse icon-history-force-white"
@click="refreshContact" />
<!-- menu actions -->
<Actions class="header-menu" menu-align="right">
<ActionLink :href="contact.url" :download="`${contact.displayName}.vcf`"
<ActionLink :href="contact.url"
:download="`${contact.displayName}.vcf`"
icon="icon-download">
{{ t('contacts', 'Download') }}
</ActionLink>
@ -99,7 +123,9 @@
</div>
<!-- qrcode -->
<Modal v-if="qrcode" id="qrcode-modal" :title="contact.displayName"
<Modal v-if="qrcode"
id="qrcode-modal"
:title="contact.displayName"
@close="closeQrModal">
<img :src="`data:image/svg+xml;base64,${qrcode}`" class="qrcode" width="400">
</Modal>
@ -115,9 +141,12 @@
<!-- passing the debounceUpdateContact so that the contact-property component contains the function
and allow us to use it on the rfcProps since the scope is forwarded to the actions -->
<ContactProperty v-for="(property, index) in sortedProperties"
:key="`${index}-${contact.key}-${property.name}`" :index="index"
:sorted-properties="sortedProperties" :property="property"
:contact="contact" :local-contact="localContact"
:key="`${index}-${contact.key}-${property.name}`"
:index="index"
:sorted-properties="sortedProperties"
:property="property"
:contact="contact"
:local-contact="localContact"
:update-contact="debounceUpdateContact" />
<!-- addressbook change select - no last property because class is not applied here,
@ -125,14 +154,19 @@
we are hijacking this... (this is supposed to be used with a ICAL.property, but to avoid code
duplication, we created a fake propModel and property with our own options here) -->
<PropertySelect v-if="addressbooksOptions.length > 1"
:prop-model="addressbookModel" :value.sync="addressbook"
:is-first-property="true" :is-last-property="true"
:prop-model="addressbookModel"
:value.sync="addressbook"
:is-first-property="true"
:is-last-property="true"
:property="{}"
class="property--addressbooks property--last property--without-actions" />
<!-- Groups always visible -->
<PropertyGroups :prop-model="groupsModel" :value.sync="groups" :contact="contact"
:is-read-only="isReadOnly" class="property--groups property--last" />
<PropertyGroups :prop-model="groupsModel"
:value.sync="groups"
:contact="contact"
:is-read-only="isReadOnly"
class="property--groups property--last" />
<!-- Last modified-->
<PropertyRev v-if="contact.rev" :value="contact.rev" />
@ -151,8 +185,8 @@ import qr from 'qr-image'
import { stringify } from 'ical.js'
import { ActionLink, ActionButton } from 'nextcloud-vue'
import rfcProps from 'Models/rfcProps'
import validate from 'Services/validate'
import rfcProps from '../models/rfcProps'
import validate from '../services/validate'
import AddNewProp from './ContactDetails/ContactDetailsAddNewProp'
import ContactAvatar from './ContactDetails/ContactDetailsAvatar'

View File

@ -29,16 +29,20 @@
<div class="property__label" />
<!-- type selector -->
<multiselect :options="availableProperties" :placeholder="t('contacts', 'Choose property type')" class="property__value"
track-by="id" label="name" @input="addProp" />
<multiselect :options="availableProperties"
:placeholder="t('contacts', 'Choose property type')"
class="property__value"
track-by="id"
label="name"
@input="addProp" />
</div>
</div>
</template>
<script>
import rfcProps from 'Models/rfcProps'
import Contact from 'Models/contact'
import PropertyTitle from 'Components/Properties/PropertyTitle'
import rfcProps from '../../models/rfcProps'
import Contact from '../../models/contact'
import PropertyTitle from '../Properties/PropertyTitle'
import ICAL from 'ical.js'
export default {

View File

@ -25,21 +25,30 @@
<div class="contact-header-avatar">
<div class="contact-header-avatar__wrapper">
<div class="contact-header-avatar__background" @click="toggleModal" />
<div v-if="contact.photo" :style="{ 'backgroundImage': `url(${contact.photoUrl})` }"
<div v-if="contact.photo"
:style="{ 'backgroundImage': `url(${contact.photoUrl})` }"
class="contact-header-avatar__photo"
@click="toggleModal" />
<div v-click-outside="closeMenu" class="contact-header-avatar__options">
<a v-tooltip.bottom="t('contacts', 'Add a new picture')" href="#" class="contact-avatar-options"
<a v-tooltip.bottom="t('contacts', 'Add a new picture')"
href="#"
class="contact-avatar-options"
:class="loading ? 'icon-loading-small' : 'icon-picture-force-white'"
@click.stop.prevent="toggleMenu" />
<input id="contact-avatar-upload" ref="uploadInput" type="file"
class="hidden" accept="image/*" @change="processFile">
<input id="contact-avatar-upload"
ref="uploadInput"
type="file"
class="hidden"
accept="image/*"
@change="processFile">
</div>
<Modal v-if="maximizeAvatar"
ref="modal" class="contact-header-modal"
size="large" :title="contact.displayName"
ref="modal"
class="contact-header-modal"
size="large"
:title="contact.displayName"
@close="toggleModal">
<template #actions>
<ActionButton v-if="!isReadOnly" icon="icon-upload" @click="selectFileInput">
@ -55,8 +64,11 @@
{{ t('contacts', 'Download picture') }}
</ActionLink>
</template>
<img ref="img" :src="contact.photoUrl" class="contact-header-modal__photo"
:style="{ width, height }" @load="updateImgSize">
<img ref="img"
:src="contact.photoUrl"
class="contact-header-modal__photo"
:style="{ width, height }"
@load="updateImgSize">
</Modal>
<!-- out of the avatar__options because of the overflow hidden -->

View File

@ -22,23 +22,34 @@
<template>
<!-- If not in the rfcProps then we don't want to display it -->
<component :is="componentInstance" v-if="propModel && propType !== 'unknown'" ref="component"
:select-type.sync="selectType" :prop-model="propModel" :value.sync="value"
:is-first-property="isFirstProperty" :property="property" :is-last-property="isLastProperty"
:class="{'property--last': isLastProperty}" :local-contact="localContact" :prop-name="propName"
:prop-type="propType" :options="sortedModelOptions" :is-read-only="isReadOnly"
@delete="deleteProp" @update="updateContact" />
<component :is="componentInstance"
v-if="propModel && propType !== 'unknown'"
ref="component"
:select-type.sync="selectType"
:prop-model="propModel"
:value.sync="value"
:is-first-property="isFirstProperty"
:property="property"
:is-last-property="isLastProperty"
:class="{'property--last': isLastProperty}"
:local-contact="localContact"
:prop-name="propName"
:prop-type="propType"
:options="sortedModelOptions"
:is-read-only="isReadOnly"
@delete="deleteProp"
@update="updateContact" />
</template>
<script>
import { Property } from 'ical.js'
import rfcProps from 'Models/rfcProps'
import Contact from 'Models/contact'
import rfcProps from '../../models/rfcProps'
import Contact from '../../models/contact'
import PropertyText from 'Components/Properties/PropertyText'
import PropertyMultipleText from 'Components/Properties/PropertyMultipleText'
import PropertyDateTime from 'Components/Properties/PropertyDateTime'
import PropertySelect from 'Components/Properties/PropertySelect'
import PropertyText from '../Properties/PropertyText'
import PropertyMultipleText from '../Properties/PropertyMultipleText'
import PropertyDateTime from '../Properties/PropertyDateTime'
import PropertySelect from '../Properties/PropertySelect'
export default {
name: 'ContactDetailsProperty',

View File

@ -1,9 +1,12 @@
<template>
<transition name="delete-slide-left">
<div v-if="!deleteTimeout" :id="id"
<div v-if="!deleteTimeout"
:id="id"
:class="{active: selectedContact === contact.key}"
tabindex="0" class="app-content-list-item"
@click.prevent.stop="selectContact" @keypress.enter.prevent.stop="selectContact">
tabindex="0"
class="app-content-list-item"
@click.prevent.stop="selectContact"
@keypress.enter.prevent.stop="selectContact">
<!-- keyboard accessibility will focus the input and not the label -->
<!--
<input ref="selected" :id="contact.key" type="checkbox"
@ -25,12 +28,17 @@
</div>
<!-- undo actions -->
<div v-if="!contact.addressbook.readOnly && !deleteTimeout" class="icon-delete" tabindex="0"
@click.prevent.stop="deleteContact" @keypress.enter.prevent.stop="deleteContact" />
<div v-if="!contact.addressbook.readOnly && !deleteTimeout"
class="icon-delete"
tabindex="0"
@click.prevent.stop="deleteContact"
@keypress.enter.prevent.stop="deleteContact" />
</div>
<!-- Deleted contact (pending) -->
<div v-else :id="id" key="deleted"
<div v-else
:id="id"
key="deleted"
class="deleted app-content-list-item">
<div :style="{ backgroundColor: 'grey' }" class="app-content-list-item-icon">
{{ contact.displayName | firstLetter }}
@ -41,9 +49,11 @@
<div class="app-content-list-item-line-one">
{{ contact.displayName }}
</div>
<div v-tooltip.auto="t('contacts', 'Deleting the contact in {countdown} seconds', { countdown })" class="icon-history"
<div v-tooltip.auto="t('contacts', 'Deleting the contact in {countdown} seconds', { countdown })"
class="icon-history"
tabindex="0"
@click.prevent.stop="cancelDeletion" @keypress.enter.prevent.stop="cancelDeletion" />
@click.prevent.stop="cancelDeletion"
@keypress.enter.prevent.stop="cancelDeletion" />
</div>
</transition>
</template>

View File

@ -25,7 +25,9 @@
<ActionButton icon="icon-delete" @click="deleteProperty">
{{ t('contacts', 'Delete') }}
</ActionButton>
<actions :is="action" v-for="(action, index) in actions" :key="index"
<actions :is="action"
v-for="(action, index) in actions"
:key="index"
:component="propertyComponent" />
</Actions>
</template>

View File

@ -23,15 +23,23 @@
<template>
<div v-if="propModel" :class="`grid-span-${gridLength}`" class="property">
<!-- title if first element -->
<PropertyTitle v-if="isFirstProperty && propModel.icon" :icon="propModel.icon" :readable-name="propModel.readableName"
<PropertyTitle v-if="isFirstProperty && propModel.icon"
:icon="propModel.icon"
:readable-name="propModel.readableName"
:info="propModel.info" />
<div class="property__row">
<!-- type selector -->
<multiselect v-if="propModel.options" v-model="localType"
:options="options" :searchable="false" :placeholder="t('contacts', 'Select type')"
:disabled="isReadOnly" class="property__label" track-by="id"
label="name" @input="updateType" />
<multiselect v-if="propModel.options"
v-model="localType"
:options="options"
:searchable="false"
:placeholder="t('contacts', 'Select type')"
:disabled="isReadOnly"
class="property__label"
track-by="id"
label="name"
@input="updateType" />
<!-- if we do not support any type on our model but one is set anyway -->
<div v-else-if="selectType" class="property__label">
@ -44,10 +52,17 @@
</div>
<!-- Real input where the picker shows -->
<DatetimePicker :value="vcardTimeLocalValue.toJSDate()" :minute-step="10" :lang="lang"
:clearable="false" :first-day-of-week="firstDay" :type="inputType"
:readonly="isReadOnly" :format="dateFormat" class="property__value"
confirm @confirm="debounceUpdateValue" />
<DatetimePicker :value="vcardTimeLocalValue.toJSDate()"
:minute-step="10"
:lang="lang"
:clearable="false"
:first-day-of-week="firstDay"
:type="inputType"
:readonly="isReadOnly"
:format="dateFormat"
class="property__value"
confirm
@confirm="debounceUpdateValue" />
<!-- props actions -->
<PropertyActions :actions="actions" :property-component="this" @delete="deleteProperty" />
@ -62,7 +77,7 @@ import { DatetimePicker } from 'nextcloud-vue'
import { getLocale } from 'nextcloud-l10n'
import { VCardTime } from 'ical.js'
import PropertyMixin from 'Mixins/PropertyMixin'
import PropertyMixin from '../../mixins/PropertyMixin'
import PropertyTitle from './PropertyTitle'
import PropertyActions from './PropertyActions'

View File

@ -30,11 +30,19 @@
</div>
<!-- multiselect taggable groups with a limit to 3 groups shown -->
<multiselect v-model="localValue" :options="groups" :placeholder="t('contacts', 'Add contact in group')"
:multiple="true" :taggable="true" :close-on-select="false"
:readonly="isReadOnly" :tag-width="60"
tag-placeholder="create" class="property__value"
@input="updateValue" @tag="validateGroup" @select="addContactToGroup"
<multiselect v-model="localValue"
:options="groups"
:placeholder="t('contacts', 'Add contact in group')"
:multiple="true"
:taggable="true"
:close-on-select="false"
:readonly="isReadOnly"
:tag-width="60"
tag-placeholder="create"
class="property__value"
@input="updateValue"
@tag="validateGroup"
@select="addContactToGroup"
@remove="removeContactToGroup">
<!-- show how many groups are hidden and add tooltip -->
<span slot="limit" v-tooltip.auto="formatGroupsTitle" class="multiselect__limit">
@ -50,7 +58,7 @@
<script>
import debounce from 'debounce'
import Contact from 'Models/contact'
import Contact from '../../models/contact'
export default {
name: 'PropertyGroups',

View File

@ -23,16 +23,25 @@
<template>
<div v-if="propModel" :class="`grid-span-${gridLength}`" class="property">
<!-- title if first element -->
<PropertyTitle v-if="isFirstProperty && propModel.icon" :icon="propModel.icon" :readable-name="propModel.readableName"
<PropertyTitle v-if="isFirstProperty && propModel.icon"
:icon="propModel.icon"
:readable-name="propModel.readableName"
:info="propModel.info" />
<div class="property__row">
<!-- type selector -->
<multiselect v-if="propModel.options" v-model="localType"
:options="options" :placeholder="t('contacts', 'Select type')"
:taggable="true" tag-placeholder="create" :disabled="isReadOnly"
class="property__label" track-by="id" label="name"
@tag="createLabel" @input="updateType" />
<multiselect v-if="propModel.options"
v-model="localType"
:options="options"
:placeholder="t('contacts', 'Select type')"
:taggable="true"
tag-placeholder="create"
:disabled="isReadOnly"
class="property__label"
track-by="id"
label="name"
@tag="createLabel"
@input="updateType" />
<!-- if we do not support any type on our model but one is set anyway -->
<div v-else-if="selectType" class="property__label">
@ -46,12 +55,17 @@
</div>
<!-- show the first input if not a structured value -->
<input v-if="!property.isStructuredValue" v-model.trim="localValue[0]" :readonly="isReadOnly"
class="property__value" type="text" @input="updateValue">
<input v-if="!property.isStructuredValue"
v-model.trim="localValue[0]"
:readonly="isReadOnly"
class="property__value"
type="text"
@input="updateValue">
<!-- props actions -->
<PropertyActions class="property__actions--floating"
:actions="actions" :property-component="this"
:actions="actions"
:property-component="this"
@delete="deleteProperty" />
</div>
@ -61,25 +75,32 @@
<div class="property__label">
{{ propModel.readableValues[index] }}
</div>
<input v-model.trim="localValue[index]" :readonly="isReadOnly" class="property__value"
type="text" @input="updateValue">
<input v-model.trim="localValue[index]"
:readonly="isReadOnly"
class="property__value"
type="text"
@input="updateValue">
</div>
</template>
<!-- no order enforced: just iterate on all the values -->
<template v-else>
<div v-for="(value, index) in filteredValue" :key="index"
<div v-for="(value, index) in filteredValue"
:key="index"
class="property__row">
<div class="property__label" />
<input v-model.trim="filteredValue[index]" :readonly="isReadOnly" class="property__value"
type="text" @input="updateValue">
<input v-model.trim="filteredValue[index]"
:readonly="isReadOnly"
class="property__value"
type="text"
@input="updateValue">
</div>
</template>
</div>
</template>
<script>
import PropertyMixin from 'Mixins/PropertyMixin'
import PropertyMixin from '../../mixins/PropertyMixin'
import PropertyTitle from './PropertyTitle'
import PropertyActions from './PropertyActions'

View File

@ -23,7 +23,9 @@
<template>
<div v-if="propModel" :class="`grid-span-${gridLength}`" class="property">
<!-- title if first element -->
<PropertyTitle v-if="isFirstProperty && propModel.icon" :icon="propModel.icon" :readable-name="propModel.readableName"
<PropertyTitle v-if="isFirstProperty && propModel.icon"
:icon="propModel.icon"
:readable-name="propModel.readableName"
:info="propModel.info" />
<div class="property__row">
@ -37,9 +39,14 @@
{{ propModel.readableName }}
</div>
<multiselect v-model="matchedOptions" :options="propModel.options" :placeholder="t('contacts', 'Select option')"
:disabled="isSingleOption || isReadOnly" class="property__value" track-by="id"
label="name" @input="updateValue" />
<multiselect v-model="matchedOptions"
:options="propModel.options"
:placeholder="t('contacts', 'Select option')"
:disabled="isSingleOption || isReadOnly"
class="property__value"
track-by="id"
label="name"
@input="updateValue" />
<!-- props actions -->
<PropertyActions :actions="actions" :property-component="this" @delete="deleteProperty" />
@ -48,7 +55,7 @@
</template>
<script>
import PropertyMixin from 'Mixins/PropertyMixin'
import PropertyMixin from '../../mixins/PropertyMixin'
import PropertyTitle from './PropertyTitle'
import PropertyActions from './PropertyActions'

View File

@ -23,16 +23,25 @@
<template>
<div v-if="propModel" :class="`grid-span-${gridLength}`" class="property">
<!-- title if first element -->
<PropertyTitle v-if="isFirstProperty && propModel.icon" :icon="propModel.icon" :readable-name="propModel.readableName"
<PropertyTitle v-if="isFirstProperty && propModel.icon"
:icon="propModel.icon"
:readable-name="propModel.readableName"
:info="propModel.info" />
<div class="property__row">
<!-- type selector -->
<multiselect v-if="propModel.options" v-model="localType"
:options="options" :placeholder="t('contacts', 'Select type')"
:taggable="true" tag-placeholder="create" :disabled="isReadOnly"
class="property__label" track-by="id" label="name"
@tag="createLabel" @input="updateType" />
<multiselect v-if="propModel.options"
v-model="localType"
:options="options"
:placeholder="t('contacts', 'Select type')"
:taggable="true"
tag-placeholder="create"
:disabled="isReadOnly"
class="property__label"
track-by="id"
label="name"
@tag="createLabel"
@input="updateType" />
<!-- if we do not support any type on our model but one is set anyway -->
<div v-else-if="selectType" class="property__label">
@ -45,18 +54,30 @@
</div>
<!-- textarea for note -->
<textarea v-if="propName === 'note'" id="textarea" ref="textarea"
v-model.trim="localValue" :type="type" :readonly="isReadOnly"
<textarea v-if="propName === 'note'"
id="textarea"
ref="textarea"
v-model.trim="localValue"
:type="type"
:readonly="isReadOnly"
class="property__value"
@input="updateValueNoDebounce" @mousemove="resizeGrid" @keypress="resizeGrid" />
@input="updateValueNoDebounce"
@mousemove="resizeGrid"
@keypress="resizeGrid" />
<!-- OR default to input -->
<input v-else v-model.trim="localValue" :type="type"
:readonly="isReadOnly" :class="{'property__value--with-ext': haveExtHandler}" class="property__value"
<input v-else
v-model.trim="localValue"
:type="type"
:readonly="isReadOnly"
:class="{'property__value--with-ext': haveExtHandler}"
class="property__value"
@input="updateValue">
<!-- external link -->
<a v-if="haveExtHandler" :href="externalHandler" class="property__ext icon-external"
<a v-if="haveExtHandler"
:href="externalHandler"
class="property__ext icon-external"
target="_blank" />
<!-- props actions -->
@ -67,7 +88,7 @@
<script>
import debounce from 'debounce'
import PropertyMixin from 'Mixins/PropertyMixin'
import PropertyMixin from '../../mixins/PropertyMixin'
import PropertyTitle from './PropertyTitle'
import PropertyActions from './PropertyActions'

View File

@ -28,10 +28,13 @@
</span>
<!-- sharing button -->
<a v-if="!addressbook.readOnly" v-tooltip.top="sharedWithTooltip"
<a v-if="!addressbook.readOnly"
v-tooltip.top="sharedWithTooltip"
:class="{'addressbook__share--shared': hasShares}"
:title="sharedWithTooltip" href="#"
class="addressbook__share icon-shared" @click="toggleShare" />
:title="sharedWithTooltip"
href="#"
class="addressbook__share icon-shared"
@click="toggleShare" />
<!-- popovermenu -->
<Actions class="addressbook__menu" menu-align="right">

View File

@ -39,14 +39,16 @@
@input="shareAddressbook" />
<!-- list of user or groups addressbook is shared with -->
<ul v-if="addressbook.shares.length > 0" class="addressbook-shares__list">
<address-book-sharee v-for="sharee in addressbook.shares" :key="sharee.uri"
:sharee="sharee" :addressbook="addressbook" />
<address-book-sharee v-for="sharee in addressbook.shares"
:key="sharee.uri"
:sharee="sharee"
:addressbook="addressbook" />
</ul>
</div>
</template>
<script>
import client from 'Services/cdav'
import client from '../../services/cdav'
import addressBookSharee from './SettingsAddressbookSharee'
import debounce from 'debounce'

View File

@ -23,10 +23,11 @@
<template>
<li class="addressbook-sharee">
<span :class="{
'icon-loading-small': loading,
'icon-group': sharee.isGroup && !loading,
'icon-user': !sharee.isGroup && !loading
}" class="icon" />
'icon-loading-small': loading,
'icon-group': sharee.isGroup && !loading,
'icon-user': !sharee.isGroup && !loading
}"
class="icon" />
<span class="addressbook-sharee__identifier">
{{ sharee.displayName }}
</span>
@ -42,7 +43,8 @@
<label :for="uid">
{{ t('contacts', 'can edit') }}
</label>
<a :class="{'addressbook-sharee__utils--disabled': loading}" href="#"
<a :class="{'addressbook-sharee__utils--disabled': loading}"
href="#"
title="Delete"
class="icon-delete"
@click="deleteSharee" />

View File

@ -23,8 +23,11 @@
<template>
<div class="import-contact">
<template v-if="!isNoAddressbookAvailable">
<input id="contact-import" :disabled="isImporting" type="file"
class="hidden-visually" @change="processFile">
<input id="contact-import"
:disabled="isImporting"
type="file"
class="hidden-visually"
@change="processFile">
<label id="upload" for="contact-import" class="button import-contact__multiselect-label icon-upload">
{{ isImporting ? t('contacts', 'Importing into') : t('contacts', 'Import into') }}
</label>
@ -36,7 +39,9 @@
label="displayName"
class="import-contact__multiselect" />
</template>
<button v-else id="upload" for="contact-import"
<button v-else
id="upload"
for="contact-import"
class="button import-contact__multiselect-label import-contact__multiselect--no-select icon-error">
{{ t('contacts', 'Importing is disabled because there are no address books available') }}
</button>

View File

@ -21,12 +21,24 @@
-->
<template>
<form id="new-addressbook-form" :disabled="loading" :class="{'icon-loading-small': loading}"
name="new-addressbook-form" class="new-addressbook" @submit.prevent.stop="addAddressbook">
<input id="new-addressbook" ref="addressbook" v-model="displayName"
:disabled="loading" :placeholder="t('contacts', 'Address book name')" :pattern="addressBookRegex"
class="new-addressbook-input" type="text" autocomplete="off"
autocorrect="off" spellcheck="false" minlength="1"
<form id="new-addressbook-form"
:disabled="loading"
:class="{'icon-loading-small': loading}"
name="new-addressbook-form"
class="new-addressbook"
@submit.prevent.stop="addAddressbook">
<input id="new-addressbook"
ref="addressbook"
v-model="displayName"
:disabled="loading"
:placeholder="t('contacts', 'Address book name')"
:pattern="addressBookRegex"
class="new-addressbook-input"
type="text"
autocomplete="off"
autocorrect="off"
spellcheck="false"
minlength="1"
required>
<input class="icon-confirm" type="submit" value="">
</form>

View File

@ -23,28 +23,30 @@
<template>
<div>
<ul id="addressbook-list">
<address-book v-for="addressbook in addressbooks" :key="addressbook.id" :addressbook="addressbook" />
<SettingsAddressbook v-for="addressbook in addressbooks" :key="addressbook.id" :addressbook="addressbook" />
</ul>
<add-address-book :addressbooks="addressbooks" />
<import-contacts :addressbooks="addressbooks" class="settings-section"
@clicked="onClickImport" @fileLoaded="onLoad" />
<sort-contacts class="settings-section" />
<SettingsNewAddressbook :addressbooks="addressbooks" />
<SettingsImportContacts :addressbooks="addressbooks"
class="settings-section"
@clicked="onClickImport"
@fileLoaded="onLoad" />
<SettingsSortContacts class="settings-section" />
</div>
</template>
<script>
import addressBook from 'Components/Settings/SettingsAddressbook'
import addAddressBook from 'Components/Settings/SettingsNewAddressbook'
import importContacts from 'Components/Settings/SettingsImportContacts'
import sortContacts from 'Components/Settings/SettingsSortContacts'
import SettingsAddressbook from './Settings/SettingsAddressbook'
import SettingsNewAddressbook from './Settings/SettingsNewAddressbook'
import SettingsImportContacts from './Settings/SettingsImportContacts'
import SettingsSortContacts from './Settings/SettingsSortContacts'
export default {
name: 'SettingsSection',
components: {
addressBook,
addAddressBook,
importContacts,
sortContacts
SettingsAddressbook,
SettingsNewAddressbook,
SettingsImportContacts,
SettingsSortContacts
},
computed: {
// store getters

View File

@ -22,7 +22,6 @@
*/
import 'core-js/stable'
import 'regenerator-runtime/runtime'
import Vue from 'vue'
import App from './ContactsRoot'

View File

@ -20,7 +20,7 @@
*
*/
import debounce from 'debounce'
import Contact from 'Models/contact'
import Contact from '../models/contact'
import ICAL from 'ical.js'
export default {

View File

@ -23,7 +23,7 @@
import Vue from 'vue'
import Router from 'vue-router'
import { generateUrl } from 'nextcloud-router'
import Contacts from 'Views/Contacts'
import Contacts from '../views/Contacts'
Vue.use(Router)

View File

@ -20,7 +20,7 @@
*
*/
import rfcProps from 'Models/rfcProps'
import rfcProps from '../../models/rfcProps'
// https://tools.ietf.org/html/rfc6350#section-6.2.7

View File

@ -20,8 +20,8 @@
*
*/
import Contact from 'Models/contact'
import Store from 'Store/index'
import Contact from '../models/contact'
import Store from '../store/index'
export default function parseVcf(data = '', addressbook) {
let regexp = /BEGIN:VCARD[\s\S]*?END:VCARD/mgi

View File

@ -20,7 +20,7 @@
*
*/
import Contact from 'Models/contact'
import Contact from '../models/contact'
import checks from './checks/'
export default function(contact) {

View File

@ -25,10 +25,10 @@ import Vue from 'vue'
import ICAL from 'ical.js'
import pLimit from 'p-limit'
import Contact from 'Models/contact'
import Contact from '../models/contact'
import client from 'Services/cdav'
import parseVcf from 'Services/parseVcf'
import client from '../services/cdav'
import parseVcf from '../services/parseVcf'
const addressbookModel = {
id: '',

View File

@ -22,8 +22,8 @@
import Vue from 'vue'
import ICAL from 'ical.js'
import Contact from 'Models/contact'
import validate from 'Services/validate'
import Contact from '../models/contact'
import validate from '../services/validate'
const sortData = (a, b) => {
var nameA = typeof a.value === 'string'

View File

@ -26,8 +26,12 @@
<!-- new-contact-button + navigation + settings -->
<AppNavigation>
<!-- new-contact-button -->
<AppNavigationNew v-if="!loading" button-id="new-contact-button" :text="t('contacts','New contact')"
button-class="icon-add" :disabled="!defaultAddressbook" @click="newContact" />
<AppNavigationNew v-if="!loading"
button-id="new-contact-button"
:text="t('contacts','New contact')"
button-class="icon-add"
:disabled="!defaultAddressbook"
@click="newContact" />
<!-- groups list -->
<ul v-if="!loading" id="groups-list">
@ -42,19 +46,26 @@
<AppContent>
<!-- go back to list when in details mode -->
<div v-if="selectedContact && isMobile" id="app-details-toggle" class="icon-confirm"
tabindex="0" @click="showList" />
<div v-if="selectedContact && isMobile"
id="app-details-toggle"
class="icon-confirm"
tabindex="0"
@click="showList" />
<div id="app-content-wrapper">
<!-- contacts list -->
<ContactsList :list="contactsList" :contacts="contacts" :loading="loading"
<ContactsList :list="contactsList"
:contacts="contacts"
:loading="loading"
:search-query="searchQuery" />
<!-- main contacts details -->
<ContactDetails :loading="loading" :contact-key="selectedContact" />
</div>
</AppContent>
<Modal v-if="isImporting" :clear-view-delay="-1" :can-close="isImportDone"
<Modal v-if="isImporting"
:clear-view-delay="-1"
:can-close="isImportDone"
@close="closeImport">
<ImportScreen />
</Modal>
@ -77,15 +88,15 @@ import moment from 'moment'
import download from 'downloadjs'
import { VCardTime } from 'ical.js'
import SettingsSection from 'Components/SettingsSection'
import ContactsList from 'Components/ContactsList'
import ContactDetails from 'Components/ContactDetails'
import ImportScreen from 'Components/ImportScreen'
import SettingsSection from '../components/SettingsSection'
import ContactsList from '../components/ContactsList'
import ContactDetails from '../components/ContactDetails'
import ImportScreen from '../components/ImportScreen'
import Contact from 'Models/contact'
import rfcProps from 'Models/rfcProps'
import Contact from '../models/contact'
import rfcProps from '../models/rfcProps'
import client from 'Services/cdav'
import client from '../services/cdav'
const GROUP_ALL_CONTACTS = t('contacts', 'All contacts')
const GROUP_NO_GROUP_CONTACTS = t('contacts', 'Not grouped')

6
tests/.eslintrc.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
env: {
mocha: true,
jest: true
}
}

View File

@ -1,4 +1,4 @@
/*
/**
* @copyright 2018 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2018 Christoph Wurst <christoph@winzerhof-wurst.at>
@ -22,6 +22,16 @@
require('jsdom-global')()
global.expect = require('chai').expect
// https://github.com/vuejs/vue-test-utils/issues/936
// better fix for "TypeError: Super expression must either be null or
// a function" than pinning an old version of prettier.
//
// https://github.com/vuejs/vue-cli/issues/2128#issuecomment-453109575
window.Date = Date
global.OC = {
getLocale: () => 'en'
}
global.t = (app, text) => text
global.n = (app, textSingular, textPlural, count) => count > 1 ? textPlural : textSingular

View File

@ -20,12 +20,13 @@
*
*/
import { mount } from '@vue/test-utils'
import Contacts from 'Views/Contacts.vue'
// eslint-disable-next-line node/no-unpublished-import
// import { mount } from '@vue/test-utils'
// import Contacts from '../../../src/views/Contacts.vue'
describe('Contacts.vue', () => {
it('Test contacts view', () => {
const wrapper = mount(Contacts)
expect(wrapper.text()).toContain('Test')
})
})
// describe('Contacts.vue', () => {
// it('Test contacts view', () => {
// const wrapper = mount(Contacts)
// expect(wrapper.text()).toContain('Test')
// })
// })

View File

@ -2,14 +2,17 @@ const path = require('path')
const webpack = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')
const StyleLintPlugin = require('stylelint-webpack-plugin')
const packageJson = require('./package.json')
const appName = packageJson.name
const appVersion = JSON.stringify(packageJson.version)
module.exports = {
entry: path.join(__dirname, 'src', 'main.js'),
output: {
path: path.resolve(__dirname, './js'),
publicPath: '/js/',
filename: 'contacts.js',
chunkFilename: 'chunks/contacts.[name].[contenthash].js'
filename: `${appName}.js`,
chunkFilename: 'chunks/[name]-[hash].js'
},
module: {
rules: [
@ -24,29 +27,18 @@ module.exports = {
{
test: /\.(js|vue)$/,
use: 'eslint-loader',
exclude: /node_modules/,
enforce: 'pre'
},
{
test: /\.vue$/,
loader: 'vue-loader'
loader: 'vue-loader',
exclude: /node_modules/
},
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
plugins: [
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-proposal-object-rest-spread'
],
presets: ['@babel/preset-env']
}
},
exclude: /node_modules\/(?!(p-limit|p-defer|p-queue|p-try|cdav-library))/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url-loader'
loader: 'babel-loader',
exclude: /node_modules/
}
]
},
@ -54,19 +46,9 @@ module.exports = {
new VueLoaderPlugin(),
new StyleLintPlugin(),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new webpack.DefinePlugin({
appVersion: JSON.stringify(require('./package.json').version)
})
new webpack.DefinePlugin({ appVersion })
],
resolve: {
alias: {
Components: path.resolve(__dirname, 'src/components/'),
Mixins: path.resolve(__dirname, 'src/mixins/'),
Models: path.resolve(__dirname, 'src/models/'),
Services: path.resolve(__dirname, 'src/services/'),
Store: path.resolve(__dirname, 'src/store/'),
Views: path.resolve(__dirname, 'src/views/')
},
extensions: ['*', '.js', '.vue', '.json']
extensions: ['*', '.js', '.vue']
}
}