diff --git a/.github/workflows/do-spaces-workflow.yml b/.github/workflows/do-spaces-workflow.yml index e1e190d..2e5311e 100644 --- a/.github/workflows/do-spaces-workflow.yml +++ b/.github/workflows/do-spaces-workflow.yml @@ -1,4 +1,4 @@ -name: Test and deploy to DigitalOcean Spaces +name: Deploy to DigitalOcean Spaces on: push diff --git a/.github/workflows/test-workflow.yml b/.github/workflows/test-workflow.yml index 6fa0882..bd0e490 100644 --- a/.github/workflows/test-workflow.yml +++ b/.github/workflows/test-workflow.yml @@ -44,3 +44,24 @@ jobs: - name: Test with sass-lint run: npm run test:sass-lint + + i18n-packs: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Read .nvmrc + run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" + id: nvm + + - name: Use Node.js (.nvmrc) + uses: actions/setup-node@v1 + with: + node-version: "${{ steps.nvm.outputs.NVMRC }}" + + - name: Install dependencies + run: npm ci + + - name: Test i18n packs integrity + run: npm run test:i18n-packs diff --git a/.gitignore b/.gitignore index 07812a4..01e7234 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ -node_modules/ -.cache/ -dist/ -dev/ -.idea/ -.vscode/ -build/ +node_modules +.cache +.idea +.vscode .DS_Store + +/build/ +/dist/ +/dev/ diff --git a/package-lock.json b/package-lock.json index faf5020..7a22fa8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -682,6 +682,26 @@ "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/parser": { @@ -2226,6 +2246,16 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "cli-spinners": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz", @@ -2251,6 +2281,14 @@ "requires": { "ansi-regex": "^3.0.0" } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } } } }, @@ -2473,6 +2511,17 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "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" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -2481,6 +2530,15 @@ "requires": { "ansi-regex": "^4.1.0" } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, @@ -2942,6 +3000,15 @@ "graceful-fs": "^4.1.6" } }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, "webpack-bundle-analyzer": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz", @@ -2961,6 +3028,19 @@ "mkdirp": "^0.5.1", "opener": "^1.5.1", "ws": "^6.0.0" + }, + "dependencies": { + "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" + } + } } } } @@ -2991,6 +3071,17 @@ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "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" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -3005,6 +3096,15 @@ "requires": { "ansi-regex": "^5.0.0" } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, @@ -4344,13 +4444,39 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } } }, "char-regex": { @@ -4678,6 +4804,26 @@ "@types/q": "^1.5.1", "chalk": "^2.4.1", "q": "^1.1.2" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, "code-point-at": { @@ -6192,6 +6338,28 @@ "find-root": "^1.0.0", "lodash": "^4.17.4", "semver": "^5.4.1" + }, + "dependencies": { + "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" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "easy-stack": { @@ -6862,6 +7030,12 @@ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "dev": true + }, "espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", @@ -10856,6 +11030,28 @@ "requires": { "chalk": "^2.3.0", "shell-quote": "^1.6.1" + }, + "dependencies": { + "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" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "launch-editor-middleware": { @@ -10982,6 +11178,26 @@ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "requires": { "chalk": "^2.0.1" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, "loglevel": { @@ -11921,6 +12137,17 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "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" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -11929,6 +12156,15 @@ "requires": { "ansi-regex": "^4.1.0" } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, @@ -12102,6 +12338,16 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "dotenv": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", @@ -12126,6 +12372,14 @@ "posthtml-render": "^1.1.5" } }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, "terser": { "version": "3.17.0", "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", @@ -12399,6 +12653,26 @@ "supports-color": "^6.1.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -13345,6 +13619,28 @@ "chalk": "^2.4.2", "source-map": "^0.6.1", "supports-color": "^6.1.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + } } }, "supports-color": { @@ -15491,11 +15787,20 @@ } }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + } } }, "supports-hyperlinks": { @@ -15543,6 +15848,26 @@ "stable": "^0.1.8", "unquote": "~1.1.1", "util.promisify": "~1.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, "symbol-tree": { diff --git a/package.json b/package.json index 7a0c0ba..4a5775f 100644 --- a/package.json +++ b/package.json @@ -9,22 +9,24 @@ }, "main": "src/nginxconfig/mount.js", "scripts": { - "build": "npm run build:clean && npm run build:template && npm run build:static && npm run build:tool", + "build": "npm run build:clean && npm run build:template && npm run build:prism && npm run build:static && npm run build:tool", "build:clean": "do-vue clean", "build:template": "do-vue template && node src/nginxconfig/build/template.js", + "build:prism": "node src/nginxconfig/build/prism.js", "build:static": "copyfiles --up 2 src/static/{*,**/*} dist", "build:tool": "vue-cli-service build src/nginxconfig/mount.js --no-clean", - "dev": "npm run build:template && npm run dev:tool", + "dev": "npm run build:template && npm run build:prism && npm run dev:tool", "dev:tool": "vue-cli-service serve src/nginxconfig/mount.js", "analyze": "npm run build:tool -- --analyze", "deploy:spaces:comment": "do-vue comment nginxconfig", - "test": "npm run test:eslint && npm run test:sass-lint && npm run test:jest", + "test": "npm run test:eslint && npm run test:sass-lint && npm run test:i18n-packs && npm run test:jest", "test:jest": "jest /test/.*.js?$", "test:fix": "npm run test:eslint:fix && npm run test:sass-lint:fix", "test:eslint": "eslint 'src/**/*.{js,vue}'", "test:eslint:fix": "npm run test:eslint -- --fix", "test:sass-lint": "sass-lint 'src/**/*.scss' --verbose --no-exit --config .sasslintrc", - "test:sass-lint:fix": "sass-lint-auto-fix 'src/**/*.scss'" + "test:sass-lint:fix": "sass-lint-auto-fix 'src/**/*.scss'", + "test:i18n-packs": "node -r esm src/nginxconfig/i18n/verify.js" }, "jest": { "testRegex": "/test/.*.js?$" @@ -65,12 +67,15 @@ "@babel/runtime": "^7.11.2", "@vue/cli-service": "^4.5.9", "babel-eslint": "^10.1.0", + "chalk": "^4.1.0", "copyfiles": "^2.4.1", "core-js": "^3.6.5", "duplicate-package-checker-webpack-plugin": "^3.0.0", "eslint": "^7.15.0", "eslint-plugin-vue": "^7.3.0", "jest": "^26.6.3", + "esm": "^3.2.25", + "node-fetch": "^2.6.1", "sass": "^1.30.0", "sass-lint": "^1.13.1", "sass-lint-auto-fix": "^0.21.2", diff --git a/src/nginxconfig/build/prism.js b/src/nginxconfig/build/prism.js new file mode 100644 index 0000000..a0937d5 --- /dev/null +++ b/src/nginxconfig/build/prism.js @@ -0,0 +1,42 @@ +/* +Copyright 2020 DigitalOcean + +This code is licensed under the MIT License. +You may obtain a copy of the License at +https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE or https://mit-license.org/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +const fs = require('fs').promises; +const path = require('path'); +const fetch = require('node-fetch'); + +const main = async () => { + const resp = await fetch('https://assets.digitalocean.com/prism/prism.css'); + const text = await resp.text(); + + // Fix $676767 -> #676767 + const fixed = text.replace(/:\s*\$((?:[0-9a-fA-F]{3}){1,2});/g, ':#$1;'); + + const buildDir = path.join(__dirname, '..', '..', '..', 'build'); + await fs.writeFile(path.join(buildDir, 'prism.css'), fixed); +}; + +main().then(() => {}); diff --git a/src/nginxconfig/i18n/en/common.js b/src/nginxconfig/i18n/en/common.js index 22d0a74..00b1786 100644 --- a/src/nginxconfig/i18n/en/common.js +++ b/src/nginxconfig/i18n/en/common.js @@ -35,8 +35,6 @@ export default { https: 'HTTPS', letsEncrypt: 'Let\'s Encrypt', python: 'Python', - docker: 'Docker', - dockerCompose: 'Docker Compose', wordPress: 'WordPress', drupal: 'Drupal', magento: 'Magento', diff --git a/src/nginxconfig/i18n/en/templates/global_sections/docker.js b/src/nginxconfig/i18n/en/templates/global_sections/docker.js index 8e9cecc..510111b 100644 --- a/src/nginxconfig/i18n/en/templates/global_sections/docker.js +++ b/src/nginxconfig/i18n/en/templates/global_sections/docker.js @@ -26,7 +26,16 @@ THE SOFTWARE. import common from '../../common'; +const docker = 'Docker'; +const dockerfile = 'Dockerfile'; + export default { - dockerfile: `Include Dockerfile to run nginx with ${common.docker}`, - dockerCompose: 'Include docker-compose to run nginx with docker-compose', + docker, + dockerfile, + dockerCompose: `${docker} Compose`, + applyDockerTweaks: `Apply ${docker} tweaks`, + applyDockerTweaksForNginx: `Apply configuration tweaks for running ${common.nginx} with ${docker}`, + applyDockerTweaksExplainer: `Updates the ${common.nginx} user to be <code class="slim">nginx</code> and the pid to <code class="slim">/var/run/nginx.pid</code>`, + includeDockerfile: `Include ${dockerfile} to run ${common.nginx} with ${docker}`, + includeDockerCompose: `Include docker-compose to run ${common.nginx} with docker-compose`, }; diff --git a/src/nginxconfig/i18n/verify.js b/src/nginxconfig/i18n/verify.js new file mode 100644 index 0000000..c1e3d5d --- /dev/null +++ b/src/nginxconfig/i18n/verify.js @@ -0,0 +1,93 @@ +/* +Copyright 2020 DigitalOcean + +This code is licensed under the MIT License. +You may obtain a copy of the License at +https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE or https://mit-license.org/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +import chalk from 'chalk'; +import defaultPack from './default'; +import * as packs from './index'; + +// Recursively get all keys in a i18n pack object fragment +const explore = packFragment => { + const foundKeys = new Set(); + + for (const [key, value] of Object.entries(packFragment)) { + // If this is an actual translation, store the key + if (typeof value === 'string') { + foundKeys.add(key); + continue; + } + + // Otherwise, assume this is another fragment and explore it recursively + explore(packFragment[key]).forEach(exploreKey => foundKeys.add(`${key}.${exploreKey}`)); + } + + return foundKeys; +}; + +// Get all the keys for the default "source" language pack +const defaultKeys = explore(packs[defaultPack]); + +// Track if we need to exit with an error +let hadError = false; + +// Work through all the packs and compare to default +for (const [pack, packData] of Object.entries(packs)) { + console.log(chalk.underline(`Language pack \`${pack}\``)); + + // We don't need to compare default to itself + if (pack === defaultPack) { + console.log(` Default pack, found ${defaultKeys.size.toLocaleString()} keys`); + console.log(chalk.reset()); + continue; + } + + // Get all the keys and the set differences + const packKeys = explore(packData); + const missingKeys = [...defaultKeys].filter(x => !packKeys.has(x)); + const extraKeys = [...packKeys].filter(x => !defaultKeys.has(x)); + + // Missing keys are errors, extra keys are just warnings + const errors = missingKeys.map(key => `Missing key \`${key}\``); + const warnings = extraKeys.map(key => `Unexpected key \`${key}\``); + + // Output the pack results + if (warnings.length) + for (const warning of warnings) + console.log(` ${chalk.yellow('warning')} ${warning}`); + if (errors.length) + for (const error of errors) + console.log(` ${chalk.red('error')} ${error}`); + if (!errors.length && !warnings.length) + console.log(` ${chalk.green('No issues, all keys present with no unexpected keys')}`); + + // If we had errors, script should exit 1 + if (errors.length) hadError = true; + + // Linebreak before next pack or exit + console.log(chalk.reset()); +} + +// Exit 1 if we had errors +if (hadError) process.exit(1); diff --git a/src/nginxconfig/i18n/zh-cn/common.js b/src/nginxconfig/i18n/zh-cn/common.js index 5e305b2..579b395 100644 --- a/src/nginxconfig/i18n/zh-cn/common.js +++ b/src/nginxconfig/i18n/zh-cn/common.js @@ -35,8 +35,6 @@ export default { https: 'HTTPS', letsEncrypt: 'Let\'s Encrypt', python: 'Python', - docker: 'Docker', - dockerCompose: 'Docker Compose', wordPress: 'WordPress', drupal: 'Drupal', magento: 'Magento', diff --git a/src/nginxconfig/i18n/zh-cn/templates/global_sections/docker.js b/src/nginxconfig/i18n/zh-cn/templates/global_sections/docker.js index 54b89b5..d9cac35 100644 --- a/src/nginxconfig/i18n/zh-cn/templates/global_sections/docker.js +++ b/src/nginxconfig/i18n/zh-cn/templates/global_sections/docker.js @@ -26,7 +26,16 @@ THE SOFTWARE. import common from '../../common'; +const docker = 'Docker'; +const dockerfile = 'Dockerfile'; + export default { - dockerfile: `生成Dockerfile运行${common.nginx}与${common.docker}`, - dockerCompose: '生成docker-compose.yaml来运行nginx docker-compose', + docker, + dockerfile, + dockerCompose: `${docker} Compose`, // TODO: translate + applyDockerTweaks: `Apply ${docker} tweaks`, // TODO: translate + applyDockerTweaksForNginx: `Apply configuration tweaks for running ${common.nginx} with ${docker}`, // TODO: translate + applyDockerTweaksExplainer: `Updates the ${common.nginx} user to be <code class="slim">nginx</code> and the pid to <code class="slim">/var/run/nginx.pid</code>`, // TODO: translate + includeDockerfile: `生成${dockerfile}运行${common.nginx}与${docker}`, + includeDockerCompose: `生成docker-compose.yaml来运行${common.nginx} docker-compose`, }; diff --git a/src/nginxconfig/i18n/zh-tw/common.js b/src/nginxconfig/i18n/zh-tw/common.js index 000cd56..808cc8f 100644 --- a/src/nginxconfig/i18n/zh-tw/common.js +++ b/src/nginxconfig/i18n/zh-tw/common.js @@ -35,8 +35,6 @@ export default { https: 'HTTPS', letsEncrypt: 'Let\'s Encrypt', python: 'Python', - docker: 'Docker', - dockerCompose: 'Docker Compose', wordPress: 'WordPress', drupal: 'Drupal', magento: 'Magento', diff --git a/src/nginxconfig/i18n/zh-tw/templates/global_sections/docker.js b/src/nginxconfig/i18n/zh-tw/templates/global_sections/docker.js index 104bff8..92cc143 100644 --- a/src/nginxconfig/i18n/zh-tw/templates/global_sections/docker.js +++ b/src/nginxconfig/i18n/zh-tw/templates/global_sections/docker.js @@ -26,7 +26,16 @@ THE SOFTWARE. import common from '../../common'; +const docker = 'Docker'; +const dockerfile = 'Dockerfile'; + export default { - dockerfile: `生成Dockerfile運行${common.nginx}與${common.docker}`, - dockerCompose: '生成docker-compose.yaml來運行nginx docker-compose', + docker, + dockerfile, + dockerCompose: `${docker} Compose`, // TODO: translate + applyDockerTweaks: `Apply ${docker} tweaks`, // TODO: translate + applyDockerTweaksForNginx: `Apply configuration tweaks for running ${common.nginx} with ${docker}`, // TODO: translate + applyDockerTweaksExplainer: `Updates the ${common.nginx} user to be <code class="slim">nginx</code> and the pid to <code class="slim">/var/run/nginx.pid</code>`, // TODO: translate + includeDockerfile: `生成${dockerfile}運行${common.nginx}與${docker}`, + includeDockerCompose: `生成docker-compose.yaml來運行${common.nginx} docker-compose`, }; diff --git a/src/nginxconfig/scss/_fields.scss b/src/nginxconfig/scss/_fields.scss index fbfc76d..4263a73 100644 --- a/src/nginxconfig/scss/_fields.scss +++ b/src/nginxconfig/scss/_fields.scss @@ -48,6 +48,14 @@ THE SOFTWARE. &.is-aligned-top { align-items: flex-start; + + > p { + @include sailec-medium; + + color: $dark-grey; + font-size: 14px; + margin: 0 .5rem; + } } + .control { @@ -118,6 +126,14 @@ THE SOFTWARE. color: $dark-grey; padding: 0 ($margin * 1.5); } + + &.is-tiny { + font-size: 14px; + height: auto; + line-height: normal; + margin: .2rem .25rem; + padding: ($margin * .5) ($margin * .75); + } } .control { diff --git a/src/nginxconfig/scss/style.scss b/src/nginxconfig/scss/style.scss index 8ab4c8d..e6964db 100644 --- a/src/nginxconfig/scss/style.scss +++ b/src/nginxconfig/scss/style.scss @@ -24,13 +24,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -@import url("https://assets.digitalocean.com/prism/prism.css"); - $header: #0071fe; $highlight: #f2c94c; @import "~do-bulma/src/style"; .do-bulma { + @import "../../../build/prism"; + $pretty--color-dark: $primary; $pretty--color-default: $primary; @import "~pretty-checkbox/src/pretty-checkbox"; diff --git a/src/nginxconfig/templates/global_sections/docker.vue b/src/nginxconfig/templates/global_sections/docker.vue index 1dcd388..103ffbb 100644 --- a/src/nginxconfig/templates/global_sections/docker.vue +++ b/src/nginxconfig/templates/global_sections/docker.vue @@ -28,7 +28,24 @@ THE SOFTWARE. <div> <div class="field is-horizontal"> <div class="field-label"> - <label class="label">{{ $t('common.docker') }}</label> + <label class="label">{{ $t('templates.globalSections.docker.docker') }}</label> + </div> + <div class="field-body"> + <div class="field is-horizontal is-aligned-top"> + <a class="button is-primary is-tiny" @click="applyDockerTweaks"> + {{ $t('templates.globalSections.docker.applyDockerTweaks') }} + </a> + <p> + {{ $t('templates.globalSections.docker.applyDockerTweaksForNginx') }} + <br /> + <small v-html="$t('templates.globalSections.docker.applyDockerTweaksExplainer')"></small> + </p> + </div> + </div> + </div> + <div class="field is-horizontal"> + <div class="field-label"> + <label class="label">{{ $t('templates.globalSections.docker.dockerfile') }}</label> </div> <div class="field-body"> <div class="field"> @@ -36,7 +53,7 @@ THE SOFTWARE. <div class="checkbox"> <PrettyCheck v-model="dockerfile" class="p-default p-curve p-fill p-icon"> <i slot="extra" class="icon fas fa-check"></i> - {{ $t('templates.globalSections.docker.dockerfile') }} + {{ $t('templates.globalSections.docker.includeDockerfile') }} </PrettyCheck> </div> </div> @@ -45,7 +62,7 @@ THE SOFTWARE. </div> <div v-if="dockerfile" class="field is-horizontal"> <div class="field-label"> - <label class="label">{{ $t('common.dockerCompose') }}</label> + <label class="label">{{ $t('templates.globalSections.docker.dockerCompose') }}</label> </div> <div class="field-body"> <div class="field"> @@ -53,7 +70,7 @@ THE SOFTWARE. <div class="checkbox"> <PrettyCheck v-model="dockerCompose" class="p-default p-curve p-fill p-icon"> <i slot="extra" class="icon fas fa-check"></i> - {{ $t('templates.globalSections.docker.dockerCompose') }} + {{ $t('templates.globalSections.docker.includeDockerCompose') }} </PrettyCheck> </div> </div> @@ -67,6 +84,7 @@ THE SOFTWARE. import PrettyCheck from 'pretty-checkbox-vue/check'; import delegatedFromDefaults from '../../util/delegated_from_defaults'; import computedFromDefaults from '../../util/computed_from_defaults'; + import analytics from '../../util/analytics'; const defaults = { dockerfile: { @@ -81,7 +99,7 @@ THE SOFTWARE. export default { name: 'GlobalDocker', // Component name - display: 'common.docker', // Display name for tab (i18n key) + display: 'templates.globalSections.docker.docker', // Display name for tab (i18n key) key: 'docker', // Key for data in parent delegated: delegatedFromDefaults(defaults), // Data the parent will present here components: { @@ -106,5 +124,13 @@ THE SOFTWARE. deep: true, }, }, + methods: { + applyDockerTweaks() { + analytics('apply_docker_tweaks', 'Presets'); + this.$parent.setValue('nginx', 'user', 'nginx'); + this.$parent.setValue('nginx', 'pid', '/var/run/nginx.pid'); + this.$parent.setValue('docker', 'dockerfile', true); + }, + }, }; </script>