diff --git a/.circleci/config.yml b/.circleci/config.yml index 3049a872a..461a0dfa6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -63,7 +63,7 @@ jobs: command: npm run test:basic - run: name: Test - Mustache Spans - command: npm run test:mustache-span + command: npm run test:mustache-syntax - run: name: Test - Routes command: npm run test:route diff --git a/.eslintrc.js b/.eslintrc.js index bc8b5c8cd..4e57c5c7f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,6 +24,7 @@ module.exports = { 'react/jsx-no-bind' : ['error', { allowArrowFunctions: true }], 'react/jsx-uses-react' : 'error', 'react/prefer-es6-class' : ['error', 'never'], + 'jest/valid-expect' : ['error', { maxArgs: 2 }], /** Warnings **/ 'max-lines' : ['warn', { diff --git a/client/homebrew/navbar/error-navitem.jsx b/client/homebrew/navbar/error-navitem.jsx index efee04019..eb2872c22 100644 --- a/client/homebrew/navbar/error-navitem.jsx +++ b/client/homebrew/navbar/error-navitem.jsx @@ -82,4 +82,4 @@ const ErrorNavItem = createClass({ } }); -module.exports = ErrorNavItem; \ No newline at end of file +module.exports = ErrorNavItem; diff --git a/client/homebrew/navbar/error-navitem.less b/client/homebrew/navbar/error-navitem.less index 8a7cabb19..7e7dab772 100644 --- a/client/homebrew/navbar/error-navitem.less +++ b/client/homebrew/navbar/error-navitem.less @@ -1,77 +1,75 @@ -.navItem { - &.error { - position : relative; - background-color : @red; - } +.navItem.error { + position : relative; + background-color : @red; +} - .errorContainer{ - animation-name: glideDown; - animation-duration: 0.4s; - position : absolute; - top : 100%; - left : 50%; - z-index : 1000; - width : 140px; - padding : 3px; - color : white; +.errorContainer{ + animation-name: glideDown; + animation-duration: 0.4s; + position : absolute; + top : 100%; + left : 50%; + z-index : 1000; + width : 140px; + padding : 3px; + color : white; + background-color : #333; + border : 3px solid #444; + border-radius : 5px; + transform : translate(-50% + 3px, 10px); + text-align : center; + font-size : 10px; + font-weight : 800; + text-transform : uppercase; + a{ + color : @teal; + } + &:before { + content: ""; + width: 0px; + height: 0px; + position: absolute; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-top: 10px solid transparent; + border-bottom: 10px solid #444; + left: 53px; + top: -23px; + } + &:after { + content: ""; + width: 0px; + height: 0px; + position: absolute; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-top: 10px solid transparent; + border-bottom: 10px solid #333; + left: 53px; + top: -19px; + } + .deny { + width : 48%; + margin : 1px; + padding : 5px; background-color : #333; - border : 3px solid #444; - border-radius : 5px; - transform : translate(-50% + 3px, 10px); - text-align : center; - font-size : 10px; - font-weight : 800; - text-transform : uppercase; - a{ - color : @teal; - } - &:before { - content: ""; - width: 0px; - height: 0px; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid transparent; - border-bottom: 10px solid #444; - left: 53px; - top: -23px; - } - &:after { - content: ""; - width: 0px; - height: 0px; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid transparent; - border-bottom: 10px solid #333; - left: 53px; - top: -19px; - } - .deny { - width : 48%; - margin : 1px; - padding : 5px; - background-color : #333; - display : inline-block; - border-left : 1px solid #666; - .animate(background-color); - &:hover{ - background-color : red; - } - } - .confirm { - width : 48%; - margin : 1px; - padding : 5px; - background-color : #333; - display : inline-block; - color : white; - .animate(background-color); - &:hover{ - background-color : teal; - } + display : inline-block; + border-left : 1px solid #666; + .animate(background-color); + &:hover{ + background-color : red; } } -} \ No newline at end of file + .confirm { + width : 48%; + margin : 1px; + padding : 5px; + background-color : #333; + display : inline-block; + color : white; + .animate(background-color); + &:hover{ + background-color : teal; + } + } +} diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 94d5aef3b..4f2e8f8a2 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -254,6 +254,15 @@ const EditPage = createClass({ } + + {this.state.alertTrashedGoogleBrew && +
+ This brew is currently in your Trash folder on Google Drive!
If you want to keep it, make sure to move it before it is deleted permanently!
+
+ OK +
+
+ } ; }, @@ -335,16 +344,6 @@ const EditPage = createClass({ const shareLink = this.processShareId(); return - - {this.state.alertTrashedGoogleBrew && -
- This brew is currently in your Trash folder on Google Drive!
If you want to keep it, make sure to move it before it is deleted permanently!
-
- OK -
-
- } - {this.state.brew.title} diff --git a/package-lock.json b/package-lock.json index 186c63ee4..729396d79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,9 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.21.3", - "@babel/plugin-transform-runtime": "^7.21.0", - "@babel/preset-env": "^7.19.4", + "@babel/core": "^7.21.4", + "@babel/plugin-transform-runtime": "^7.21.4", + "@babel/preset-env": "^7.21.4", "@babel/preset-react": "^7.18.6", "@googleapis/drive": "^5.0.2", "body-parser": "^1.20.2", @@ -36,7 +36,7 @@ "mongoose": "^7.0.3", "nanoid": "3.3.4", "nconf": "^0.12.0", - "npm": "^9.6.2", + "npm": "^9.6.4", "react": "^17.0.2", "react-dom": "^17.0.2", "react-frame-component": "5.2.6", @@ -68,9 +68,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dependencies": { "@babel/highlight": "^7.18.6" }, @@ -79,28 +79,28 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", - "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", + "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", + "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-compilation-targets": "^7.20.7", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", + "@babel/helper-compilation-targets": "^7.21.4", "@babel/helper-module-transforms": "^7.21.2", "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", + "@babel/parser": "^7.21.4", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/traverse": "^7.21.4", + "@babel/types": "^7.21.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -116,11 +116,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", + "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", "dependencies": { - "@babel/types": "^7.21.3", + "@babel/types": "^7.21.4", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -166,12 +166,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", + "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", + "@babel/compat-data": "^7.21.4", + "@babel/helper-validator-option": "^7.21.0", "browserslist": "^4.21.3", "lru-cache": "^5.1.1", "semver": "^6.3.0" @@ -289,11 +289,11 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", + "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.21.4" }, "engines": { "node": ">=6.9.0" @@ -467,9 +467,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1408,11 +1408,11 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.0.tgz", - "integrity": "sha512-ReY6pxwSzEU0b3r2/T/VhqMKg/AkceBT19X0UptA3/tYi5Pe2eXgEUH+NNMC5nok6c6XQz5tyVTUpuezRfSMSg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.4.tgz", + "integrity": "sha512-1J4dhrw1h1PqnNNpzwxQ2UBymJUF8KuPjAAnlLwZcGhHAIqUigFW7cdK6GHoB64ubY4qXQNYknoUeks4Wz7CUA==", "dependencies": { - "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-module-imports": "^7.21.4", "@babel/helper-plugin-utils": "^7.20.2", "babel-plugin-polyfill-corejs2": "^0.3.3", "babel-plugin-polyfill-corejs3": "^0.6.0", @@ -1527,30 +1527,30 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", - "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.21.4.tgz", + "integrity": "sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==", "dependencies": { - "@babel/compat-data": "^7.20.1", - "@babel/helper-compilation-targets": "^7.20.0", + "@babel/compat-data": "^7.21.4", + "@babel/helper-compilation-targets": "^7.21.4", "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.18.6", + "@babel/helper-validator-option": "^7.21.0", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.20.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.20.7", + "@babel/plugin-proposal-async-generator-functions": "^7.20.7", "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.21.0", "@babel/plugin-proposal-dynamic-import": "^7.18.6", "@babel/plugin-proposal-export-namespace-from": "^7.18.9", "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-logical-assignment-operators": "^7.20.7", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.20.2", + "@babel/plugin-proposal-object-rest-spread": "^7.20.7", "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.21.0", "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -1567,40 +1567,40 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.20.7", + "@babel/plugin-transform-async-to-generator": "^7.20.7", "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.20.2", - "@babel/plugin-transform-classes": "^7.20.2", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.20.2", + "@babel/plugin-transform-block-scoping": "^7.21.0", + "@babel/plugin-transform-classes": "^7.21.0", + "@babel/plugin-transform-computed-properties": "^7.20.7", + "@babel/plugin-transform-destructuring": "^7.21.3", "@babel/plugin-transform-dotall-regex": "^7.18.6", "@babel/plugin-transform-duplicate-keys": "^7.18.9", "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-for-of": "^7.21.0", "@babel/plugin-transform-function-name": "^7.18.9", "@babel/plugin-transform-literals": "^7.18.9", "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.19.6", - "@babel/plugin-transform-modules-commonjs": "^7.19.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.6", + "@babel/plugin-transform-modules-amd": "^7.20.11", + "@babel/plugin-transform-modules-commonjs": "^7.21.2", + "@babel/plugin-transform-modules-systemjs": "^7.20.11", "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.20.5", "@babel/plugin-transform-new-target": "^7.18.6", "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.20.1", + "@babel/plugin-transform-parameters": "^7.21.3", "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.20.5", "@babel/plugin-transform-reserved-words": "^7.18.6", "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-spread": "^7.20.7", "@babel/plugin-transform-sticky-regex": "^7.18.6", "@babel/plugin-transform-template-literals": "^7.18.9", "@babel/plugin-transform-typeof-symbol": "^7.18.9", "@babel/plugin-transform-unicode-escapes": "^7.18.10", "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.20.2", + "@babel/types": "^7.21.4", "babel-plugin-polyfill-corejs2": "^0.3.3", "babel-plugin-polyfill-corejs3": "^0.6.0", "babel-plugin-polyfill-regenerator": "^0.4.1", @@ -1678,18 +1678,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", + "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/parser": "^7.21.4", + "@babel/types": "^7.21.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1698,9 +1698,9 @@ } }, "node_modules/@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -9576,9 +9576,9 @@ } }, "node_modules/npm": { - "version": "9.6.2", - "resolved": "https://registry.npmjs.org/npm/-/npm-9.6.2.tgz", - "integrity": "sha512-TnXoXhlFkH/9wI4+aXSq0aPLwKG7Ge17t1ME4/rQt+0DZWQCRk9PwhBuX/shqdUiHeKicSLSkzWx+QZgTRE+/A==", + "version": "9.6.4", + "resolved": "https://registry.npmjs.org/npm/-/npm-9.6.4.tgz", + "integrity": "sha512-8/Mct0X/w77PmgIpSlXfNIOlrZBfT+8966zLCxOhwi1qZ2Ueyy99uWPSDW6bt2OKw1NzrvHJBSgkzAvn1iWuhw==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -9649,14 +9649,14 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.2.5", - "@npmcli/config": "^6.1.4", - "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/arborist": "^6.2.7", + "@npmcli/config": "^6.1.5", + "@npmcli/map-workspaces": "^3.0.3", "@npmcli/package-json": "^3.0.0", "@npmcli/run-script": "^6.0.0", "abbrev": "^2.0.0", "archy": "~1.0.0", - "cacache": "^17.0.4", + "cacache": "^17.0.5", "chalk": "^4.1.2", "ci-info": "^3.8.0", "cli-columns": "^4.0.0", @@ -9664,33 +9664,33 @@ "columnify": "^1.6.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.1", - "glob": "^8.1.0", - "graceful-fs": "^4.2.10", + "glob": "^9.3.2", + "graceful-fs": "^4.2.11", "hosted-git-info": "^6.1.1", "ini": "^3.0.1", "init-package-json": "^5.0.0", "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^3.0.0", "libnpmaccess": "^7.0.2", - "libnpmdiff": "^5.0.13", - "libnpmexec": "^5.0.13", - "libnpmfund": "^4.0.13", + "libnpmdiff": "^5.0.15", + "libnpmexec": "^5.0.15", + "libnpmfund": "^4.0.15", "libnpmhook": "^9.0.3", "libnpmorg": "^5.0.3", - "libnpmpack": "^5.0.13", - "libnpmpublish": "^7.1.2", + "libnpmpack": "^5.0.15", + "libnpmpublish": "^7.1.3", "libnpmsearch": "^6.0.2", "libnpmteam": "^5.0.3", "libnpmversion": "^4.0.2", "make-fetch-happen": "^11.0.3", - "minimatch": "^6.2.0", - "minipass": "^4.2.4", + "minimatch": "^7.4.3", + "minipass": "^4.2.5", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", "node-gyp": "^9.3.1", - "nopt": "^7.0.0", + "nopt": "^7.1.0", "npm-audit-report": "^4.0.0", - "npm-install-checks": "^6.0.0", + "npm-install-checks": "^6.1.0", "npm-package-arg": "^10.1.0", "npm-pick-manifest": "^8.0.1", "npm-profile": "^7.0.1", @@ -9699,14 +9699,14 @@ "npmlog": "^7.0.1", "p-map": "^4.0.0", "pacote": "^15.1.1", - "parse-conflict-json": "^3.0.0", + "parse-conflict-json": "^3.0.1", "proc-log": "^3.0.0", "qrcode-terminal": "^0.12.0", "read": "^2.0.0", - "read-package-json": "^6.0.0", + "read-package-json": "^6.0.1", "read-package-json-fast": "^3.0.2", "semver": "^7.3.8", - "ssri": "^10.0.1", + "ssri": "^10.0.2", "tar": "^6.1.13", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", @@ -9755,7 +9755,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "6.2.5", + "version": "6.2.7", "inBundle": true, "license": "ISC", "dependencies": { @@ -9775,7 +9775,7 @@ "hosted-git-info": "^6.1.1", "json-parse-even-better-errors": "^3.0.0", "json-stringify-nice": "^1.1.4", - "minimatch": "^6.1.6", + "minimatch": "^7.4.2", "nopt": "^7.0.0", "npm-install-checks": "^6.0.0", "npm-package-arg": "^10.1.0", @@ -9786,7 +9786,7 @@ "parse-conflict-json": "^3.0.0", "proc-log": "^3.0.0", "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", + "promise-call-limit": "^1.0.2", "read-package-json-fast": "^3.0.2", "semver": "^7.3.7", "ssri": "^10.0.1", @@ -9801,7 +9801,7 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "6.1.4", + "version": "6.1.5", "inBundle": true, "license": "ISC", "dependencies": { @@ -9840,13 +9840,12 @@ } }, "node_modules/npm/node_modules/@npmcli/git": { - "version": "4.0.3", + "version": "4.0.4", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/promise-spawn": "^6.0.0", "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", "npm-pick-manifest": "^8.0.0", "proc-log": "^3.0.0", "promise-inflight": "^1.0.1", @@ -9874,13 +9873,13 @@ } }, "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "3.0.2", + "version": "3.0.3", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/name-from-folder": "^2.0.0", - "glob": "^8.0.1", - "minimatch": "^6.1.6", + "glob": "^9.3.1", + "minimatch": "^7.4.2", "read-package-json-fast": "^3.0.0" }, "engines": { @@ -9994,11 +9993,11 @@ } }, "node_modules/npm/node_modules/@tufjs/models": { - "version": "1.0.0", + "version": "1.0.1", "inBundle": true, "license": "MIT", "dependencies": { - "minimatch": "^6.1.0" + "minimatch": "^7.4.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -10189,13 +10188,13 @@ } }, "node_modules/npm/node_modules/cacache": { - "version": "17.0.4", + "version": "17.0.5", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", - "glob": "^8.0.1", + "glob": "^9.3.1", "lru-cache": "^7.7.1", "minipass": "^4.0.0", "minipass-collect": "^1.0.2", @@ -10515,36 +10514,24 @@ } }, "node_modules/npm/node_modules/glob": { - "version": "8.1.0", + "version": "9.3.2", "inBundle": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm/node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.10", + "version": "4.2.11", "inBundle": true, "license": "ISC" }, @@ -10653,11 +10640,11 @@ "license": "BSD-3-Clause" }, "node_modules/npm/node_modules/ignore-walk": { - "version": "6.0.1", + "version": "6.0.2", "inBundle": true, "license": "ISC", "dependencies": { - "minimatch": "^6.1.6" + "minimatch": "^7.4.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -10801,7 +10788,7 @@ "license": "MIT" }, "node_modules/npm/node_modules/just-diff": { - "version": "5.2.0", + "version": "6.0.2", "inBundle": true, "license": "MIT" }, @@ -10823,16 +10810,16 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "5.0.13", + "version": "5.0.15", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.5", + "@npmcli/arborist": "^6.2.7", "@npmcli/disparity-colors": "^3.0.0", "@npmcli/installed-package-contents": "^2.0.2", "binary-extensions": "^2.2.0", "diff": "^5.1.0", - "minimatch": "^6.1.6", + "minimatch": "^7.4.2", "npm-package-arg": "^10.1.0", "pacote": "^15.0.8", "tar": "^6.1.13" @@ -10842,11 +10829,11 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "5.0.13", + "version": "5.0.15", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.5", + "@npmcli/arborist": "^6.2.7", "@npmcli/run-script": "^6.0.0", "chalk": "^4.1.0", "ci-info": "^3.7.1", @@ -10864,11 +10851,11 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "4.0.13", + "version": "4.0.15", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.5" + "@npmcli/arborist": "^6.2.7" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -10899,11 +10886,11 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "5.0.13", + "version": "5.0.15", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.5", + "@npmcli/arborist": "^6.2.7", "@npmcli/run-script": "^6.0.0", "npm-package-arg": "^10.1.0", "pacote": "^15.0.8" @@ -10913,7 +10900,7 @@ } }, "node_modules/npm/node_modules/libnpmpublish": { - "version": "7.1.2", + "version": "7.1.3", "inBundle": true, "license": "ISC", "dependencies": { @@ -11002,7 +10989,7 @@ } }, "node_modules/npm/node_modules/minimatch": { - "version": "6.2.0", + "version": "7.4.3", "inBundle": true, "license": "ISC", "dependencies": { @@ -11016,7 +11003,7 @@ } }, "node_modules/npm/node_modules/minipass": { - "version": "4.2.4", + "version": "4.2.5", "inBundle": true, "license": "ISC", "engines": { @@ -11469,7 +11456,7 @@ } }, "node_modules/npm/node_modules/node-gyp/node_modules/readable-stream": { - "version": "3.6.1", + "version": "3.6.2", "inBundle": true, "license": "MIT", "dependencies": { @@ -11529,7 +11516,7 @@ } }, "node_modules/npm/node_modules/nopt": { - "version": "7.0.0", + "version": "7.1.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -11579,7 +11566,7 @@ } }, "node_modules/npm/node_modules/npm-install-checks": { - "version": "6.0.0", + "version": "6.1.0", "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -11741,12 +11728,12 @@ } }, "node_modules/npm/node_modules/parse-conflict-json": { - "version": "3.0.0", + "version": "3.0.1", "inBundle": true, "license": "ISC", "dependencies": { "json-parse-even-better-errors": "^3.0.0", - "just-diff": "^5.0.1", + "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" }, "engines": { @@ -11761,6 +11748,21 @@ "node": ">=0.10.0" } }, + "node_modules/npm/node_modules/path-scurry": { + "version": "1.6.3", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^7.14.1", + "minipass": "^4.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/npm/node_modules/postcss-selector-parser": { "version": "6.0.11", "inBundle": true, @@ -11798,7 +11800,7 @@ } }, "node_modules/npm/node_modules/promise-call-limit": { - "version": "1.0.1", + "version": "1.0.2", "inBundle": true, "license": "ISC", "funding": { @@ -11860,11 +11862,11 @@ } }, "node_modules/npm/node_modules/read-package-json": { - "version": "6.0.0", + "version": "6.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "glob": "^8.0.1", + "glob": "^9.3.0", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^5.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -12007,7 +12009,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/sigstore": { - "version": "1.1.1", + "version": "1.2.0", "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -12081,12 +12083,12 @@ } }, "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.12", + "version": "3.0.13", "inBundle": true, "license": "CC0-1.0" }, "node_modules/npm/node_modules/ssri": { - "version": "10.0.1", + "version": "10.0.2", "inBundle": true, "license": "ISC", "dependencies": { @@ -12196,11 +12198,11 @@ } }, "node_modules/npm/node_modules/tuf-js": { - "version": "1.1.1", + "version": "1.1.2", "inBundle": true, "license": "MIT", "dependencies": { - "@tufjs/models": "1.0.0", + "@tufjs/models": "1.0.1", "make-fetch-happen": "^11.0.1" }, "engines": { diff --git a/package.json b/package.json index b7a860b52..2ac8c1681 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,10 @@ "test:coverage": "jest --coverage --silent --runInBand", "test:dev": "jest --verbose --watch", "test:basic": "jest tests/markdown/basic.test.js --verbose", - "test:mustache-span": "jest tests/markdown/mustache-span.test.js --verbose", + "test:mustache-syntax": "jest '.*(mustache-syntax).*' --verbose --noStackTrace", + "test:mustache-syntax:inline": "jest '.*(mustache-syntax).*' -t '^Inline:.*' --verbose --noStackTrace", + "test:mustache-syntax:block": "jest '.*(mustache-syntax).*' -t '^Block:.*' --verbose --noStackTrace", + "test:mustache-syntax:injection": "jest '.*(mustache-syntax).*' -t '^Injection:.*' --verbose --noStackTrace", "test:route": "jest tests/routes/static-pages.test.js --verbose", "phb": "node scripts/phb.js", "prod": "set NODE_ENV=production && npm run build", @@ -45,20 +48,21 @@ "coveragePathIgnorePatterns": [ "build/*" ], - "coverageThreshold" : { - "global" : { - "statements" : 25, - "branches" : 10, - "functions" : 22, - "lines" : 25 + "coverageThreshold": { + "global": { + "statements": 25, + "branches": 10, + "functions": 22, + "lines": 25 }, - "server/homebrew.api.js" : { - "statements" : 65, - "branches" : 50, - "functions" : 60, - "lines" : 70 + "server/homebrew.api.js": { + "statements": 65, + "branches": 50, + "functions": 60, + "lines": 70 } - } + }, + "setupFilesAfterEnv": ["jest-expect-message"] }, "babel": { "presets": [ @@ -70,9 +74,9 @@ ] }, "dependencies": { - "@babel/core": "^7.21.3", - "@babel/plugin-transform-runtime": "^7.21.0", - "@babel/preset-env": "^7.19.4", + "@babel/core": "^7.21.4", + "@babel/plugin-transform-runtime": "^7.21.4", + "@babel/preset-env": "^7.21.4", "@babel/preset-react": "^7.18.6", "@googleapis/drive": "^5.0.2", "body-parser": "^1.20.2", @@ -96,7 +100,7 @@ "mongoose": "^7.0.3", "nanoid": "3.3.4", "nconf": "^0.12.0", - "npm": "^9.6.2", + "npm": "^9.6.4", "react": "^17.0.2", "react-dom": "^17.0.2", "react-frame-component": "5.2.6", @@ -109,6 +113,7 @@ "eslint": "^8.37.0", "eslint-plugin-react": "^7.32.2", "jest": "^29.5.0", + "jest-expect-message": "^1.1.3", "supertest": "^6.3.3" } } diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 6f5fcb1ef..39fa021e5 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -305,7 +305,7 @@ If you believe you should have access to this brew, ask the file owner to invite if(brew.authors.length === 0) { // Delete brew if there are no authors left - await brew.remove() + await HomebrewModel.deleteOne({ _id: brew._id }) .catch((err)=>{ console.error(err); throw { status: 500, message: 'Error while removing' }; diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 5ab6ac4fc..c6443be7b 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -10,7 +10,6 @@ describe('Tests for api', ()=>{ let modelBrew; let saveFunc; - let removeFunc; let markModifiedFunc; let saved; @@ -20,18 +19,15 @@ describe('Tests for api', ()=>{ saved = { ...this, _id: '1' }; return saved; }); - removeFunc = jest.fn(async function() {}); markModifiedFunc = jest.fn(()=>true); modelBrew = (brew)=>({ ...brew, save : saveFunc, - remove : removeFunc, markModified : markModifiedFunc, toObject : function() { delete this.save; delete this.toObject; - delete this.remove; delete this.markModified; return this; } @@ -569,13 +565,14 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); const req = {}; await api.deleteBrew(req, res); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).toHaveBeenCalled(); + expect(model.deleteOne).toHaveBeenCalled(); }); it('should throw on delete error', async ()=>{ @@ -587,7 +584,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); - removeFunc = jest.fn(async ()=>{ throw 'err'; }); + model.deleteOne = jest.fn(async ()=>{ throw 'err'; }); const req = {}; let err; @@ -600,7 +597,7 @@ brew`); expect(err).not.toBeUndefined(); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).toHaveBeenCalled(); + expect(model.deleteOne).toHaveBeenCalled(); }); it('should delete when one author', async ()=>{ @@ -612,13 +609,14 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); const req = { account: { username: 'test' } }; await api.deleteBrew(req, res); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).toHaveBeenCalled(); + expect(model.deleteOne).toHaveBeenCalled(); }); it('should remove one author when multiple present', async ()=>{ @@ -630,6 +628,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); const req = { account: { username: 'test' } }; await api.deleteBrew(req, res); @@ -637,7 +636,7 @@ brew`); expect(api.getBrew).toHaveBeenCalled(); expect(markModifiedFunc).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).not.toHaveBeenCalled(); + expect(model.deleteOne).not.toHaveBeenCalled(); expect(saveFunc).toHaveBeenCalled(); expect(saved.authors).toEqual(['test2']); }); @@ -651,6 +650,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); saveFunc = jest.fn(async ()=>{ throw 'err'; }); const req = { account: { username: 'test' } }; @@ -664,7 +664,7 @@ brew`); expect(err).not.toBeUndefined(); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).not.toHaveBeenCalled(); + expect(model.deleteOne).not.toHaveBeenCalled(); expect(saveFunc).toHaveBeenCalled(); }); @@ -677,6 +677,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); api.deleteGoogleBrew = jest.fn(async ()=>true); const req = { account: { username: 'test' } }; @@ -684,7 +685,7 @@ brew`); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).toHaveBeenCalled(); + expect(model.deleteOne).toHaveBeenCalled(); expect(api.deleteGoogleBrew).toHaveBeenCalled(); }); @@ -697,6 +698,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); api.deleteGoogleBrew = jest.fn(async ()=>{ throw 'err'; }); @@ -706,7 +708,7 @@ brew`); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).toHaveBeenCalled(); + expect(model.deleteOne).toHaveBeenCalled(); expect(api.deleteGoogleBrew).toHaveBeenCalled(); }); @@ -719,6 +721,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); api.deleteGoogleBrew = jest.fn(async ()=>true); const req = { account: { username: 'test' } }; @@ -727,7 +730,7 @@ brew`); expect(api.getBrew).toHaveBeenCalled(); expect(markModifiedFunc).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).not.toHaveBeenCalled(); + expect(model.deleteOne).not.toHaveBeenCalled(); expect(api.deleteGoogleBrew).toHaveBeenCalled(); expect(saveFunc).toHaveBeenCalled(); expect(saved.authors).toEqual(['test2']); @@ -745,6 +748,7 @@ brew`); req.brew = brew; }); model.findOne = jest.fn(async ()=>modelBrew(brew)); + model.deleteOne = jest.fn(async ()=>{}); api.deleteGoogleBrew = jest.fn(async ()=>true); const req = { account: { username: 'test2' } }; @@ -752,7 +756,7 @@ brew`); expect(api.getBrew).toHaveBeenCalled(); expect(model.findOne).toHaveBeenCalled(); - expect(removeFunc).not.toHaveBeenCalled(); + expect(model.deleteOne).not.toHaveBeenCalled(); expect(api.deleteGoogleBrew).not.toHaveBeenCalled(); expect(saveFunc).toHaveBeenCalled(); expect(saved.authors).toEqual(['test']); diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 16623b8a5..1960776d3 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -134,7 +134,7 @@ const mustacheInjectInline = { const match = inlineRegex.exec(src); if(match) { const lastToken = tokens[tokens.length - 1]; - if(!lastToken) + if(!lastToken || lastToken.type == 'mustacheInjectInline') return false; const tags = ` ${processStyleTags(match[1])}`; @@ -169,7 +169,7 @@ const mustacheInjectBlock = { const match = inlineRegex.exec(src); if(match) { const lastToken = tokens[tokens.length - 1]; - if(!lastToken) + if(!lastToken || lastToken.type == 'mustacheInjectBlock') return false; lastToken.originalType = 'mustacheInjectBlock'; diff --git a/tests/markdown/mustache-span.test.js b/tests/markdown/mustache-span.test.js deleted file mode 100644 index 6d249ebcb..000000000 --- a/tests/markdown/mustache-span.test.js +++ /dev/null @@ -1,128 +0,0 @@ -/* eslint-disable max-lines */ - -const Markdown = require('naturalcrit/markdown.js'); - -test('Renders a mustache span with text only', function() { - const source = '{{ text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text only, but with spaces', function() { - const source = '{{ this is a text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('this is a text'); -}); - -test('Renders an empty mustache span', function() { - const source = '{{}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe(''); -}); - -test('Renders a mustache span with just a space', function() { - const source = '{{ }}'; - const rendered = Markdown.render(source); - expect(rendered).toBe(''); -}); - -test('Renders a mustache span with a few spaces only', function() { - const source = '{{ }}'; - const rendered = Markdown.render(source); - expect(rendered).toBe(''); -}); - -test('Renders a mustache span with text and class', function() { - const source = '{{my-class text}}'; - const rendered = Markdown.render(source); - // FIXME: why do we have those two extra spaces after closing "? - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and two classes', function() { - const source = '{{my-class,my-class2 text}}'; - const rendered = Markdown.render(source); - // FIXME: why do we have those two extra spaces after closing "? - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text with spaces and class', function() { - const source = '{{my-class this is a text}}'; - const rendered = Markdown.render(source); - // FIXME: why do we have those two extra spaces after closing "? - expect(rendered).toBe('this is a text'); -}); - -test('Renders a mustache span with text and id', function() { - const source = '{{#my-span text}}'; - const rendered = Markdown.render(source); - // FIXME: why do we have that one extra space after closing "? - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and two ids', function() { - const source = '{{#my-span,#my-favorite-span text}}'; - const rendered = Markdown.render(source); - // FIXME: do we need to report an error here somehow? - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and css property', function() { - const source = '{{color:red text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and two css properties', function() { - const source = '{{color:red,padding:5px text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and css property which contains quotes', function() { - const source = '{{font:"trebuchet ms" text}}'; - const rendered = Markdown.render(source); - // FIXME: is it correct to remove quotes surrounding css property value? - expect(rendered).toBe('text'); -}); - -test('Renders a mustache span with text and two css properties which contains quotes', function() { - const source = '{{font:"trebuchet ms",padding:"5px 10px" text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text'); -}); - - -test('Renders a mustache span with text with quotes and css property which contains quotes', function() { - const source = '{{font:"trebuchet ms" text "with quotes"}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text “with quotes”'); -}); - -test('Renders a mustache span with text, id, class and a couple of css properties', function() { - const source = '{{pen,#author,color:orange,font-family:"trebuchet ms" text}}'; - const rendered = Markdown.render(source); - expect(rendered).toBe('text'); -}); - -// TODO: add tests for ID with accordance to CSS spec: -// -// From https://drafts.csswg.org/selectors/#id-selectors: -// -// > An ID selector consists of a “number sign” (U+0023, #) immediately followed by the ID value, which must be a CSS identifier. -// -// From: https://www.w3.org/TR/CSS21/syndata.html#value-def-identifier: -// -// > In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9] -// > and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_); -// > they cannot start with a digit, two hyphens, or a hyphen followed by a digit. -// > Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code (see next item). -// > For instance, the identifier "B&W?" may be written as "B\&W\?" or "B\26 W\3F". -// > Note that Unicode is code-by-code equivalent to ISO 10646 (see [UNICODE] and [ISO10646]). - -// TODO: add tests for class with accordance to CSS spec: -// -// From: https://drafts.csswg.org/selectors/#class-html: -// -// > The class selector is given as a full stop (. U+002E) immediately followed by an identifier. - diff --git a/tests/markdown/mustache-syntax.test.js b/tests/markdown/mustache-syntax.test.js new file mode 100644 index 000000000..f75ce746a --- /dev/null +++ b/tests/markdown/mustache-syntax.test.js @@ -0,0 +1,376 @@ +/* eslint-disable max-lines */ + +const dedent = require('dedent-tabs').default; +const Markdown = require('naturalcrit/markdown.js'); + +// Marked.js adds line returns after closing tags on some default tokens. +// This removes those line returns for comparison sake. +String.prototype.trimReturns = function(){ + return this.replace(/\r?\n|\r/g, ''); +}; + +// Adding `.failing()` method to `describe` or `it` will make failing tests "pass" as long as they continue to fail. +// Remove the `.failing()` method once you have fixed the issue. + +describe('Inline: When using the Inline syntax {{ }}', ()=>{ + it.failing('Renders a mustache span with text only', function() { + const source = '{{ text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text only, but with spaces', function() { + const source = '{{ this is a text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('this is a text'); + }); + + it.failing('Renders an empty mustache span', function() { + const source = '{{}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(''); + }); + + it.failing('Renders a mustache span with just a space', function() { + const source = '{{ }}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(''); + }); + + it.failing('Renders a mustache span with a few spaces only', function() { + const source = '{{ }}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(''); + }); + + it.failing('Renders a mustache span with text and class', function() { + const source = '{{my-class text}}'; + const rendered = Markdown.render(source); + // FIXME: adds two extra \s before closing `>` in opening tag. + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and two classes', function() { + const source = '{{my-class,my-class2 text}}'; + const rendered = Markdown.render(source); + // FIXME: adds two extra \s before closing `>` in opening tag. + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text with spaces and class', function() { + const source = '{{my-class this is a text}}'; + const rendered = Markdown.render(source); + // FIXME: adds two extra \s before closing `>` in opening tag + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('this is a text'); + }); + + it.failing('Renders a mustache span with text and id', function() { + const source = '{{#my-span text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s before closing `>` in opening tag, and another after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and two ids', function() { + const source = '{{#my-span,#my-favorite-span text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s before closing `>` in opening tag, and another after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and css property', function() { + const source = '{{color:red text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and two css properties', function() { + const source = '{{color:red,padding:5px text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and css property which contains quotes', function() { + const source = '{{font-family:"trebuchet ms" text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a mustache span with text and two css properties which contains quotes', function() { + const source = '{{font-family:"trebuchet ms",padding:"5px 10px" text}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + + it.failing('Renders a mustache span with text with quotes and css property which contains quotes', function() { + const source = '{{font-family:"trebuchet ms" text "with quotes"}}'; + const rendered = Markdown.render(source); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }, `Input:\n${source}`, { showPrefix: false }).toBe('text “with quotes”'); + }); + + it('Renders a mustache span with text, id, class and a couple of css properties', function() { + const source = '{{pen,#author,color:orange,font-family:"trebuchet ms" text}}'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); +}); + +// BLOCK SYNTAX + +describe(`Block: When using the Block syntax {{tags\\ntext\\n}}`, ()=>{ + it.failing('Renders a div with text only', function() { + const source = dedent`{{ + text + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }, `Input:\n${source}`, { showPrefix: false }).toBe(`

text

`); + }); + + it.failing('Renders an empty div', function() { + const source = dedent`{{ + + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds extra \s after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }, `Input:\n${source}`, { showPrefix: false }).toBe(`
`); + }); + + it('Renders a single paragraph with opening and closing brackets', function() { + const source = dedent`{{ + }}`; + const rendered = Markdown.render(source).trimReturns(); + // this actually renders in HB as '{{ }}'... + expect(rendered, `Input:\n${source}`, { showPrefix: false }, `Input:\n${source}`, { showPrefix: false }).toBe(`

{{}}

`); + }); + + it.failing('Renders a div with a single class', function() { + const source = dedent`{{cat + + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds two extra \s before closing `>` in opening tag + expect(rendered, `Input:\n${source}`, { showPrefix: false }, `Input:\n${source}`, { showPrefix: false }).toBe(`
`); + }); + + it.failing('Renders a div with a single class and text', function() { + const source = dedent`{{cat + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds two extra \s before closing `>` in opening tag + expect(rendered, `Input:\n${source}`, { showPrefix: false }, `Input:\n${source}`, { showPrefix: false }).toBe(`

Sample text.

`); + }); + + it.failing('Renders a div with two classes and text', function() { + const source = dedent`{{cat,dog + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds two extra \s before closing `>` in opening tag + expect(rendered, `Input:\n${source}`, { showPrefix: false }, `Input:\n${source}`, { showPrefix: false }).toBe(`

Sample text.

`); + }); + + it.failing('Renders a div with a style and text', function() { + const source = dedent`{{color:red + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds two extra \s before closing `>` in opening tag + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Sample text.

`); + }); + + it.failing('Renders a div with a class, style and text', function() { + const source = dedent`{{cat,color:red + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds extra \s after the class attribute + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Sample text.

`); + }); + + it('Renders a div with an ID, class, style and text (different order)', function() { + const source = dedent`{{color:red,cat,#dog + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Sample text.

`); + }); + + it.failing('Renders a div with a single ID', function() { + const source = dedent`{{#cat,#dog + Sample text. + }}`; + const rendered = Markdown.render(source).trimReturns(); + // FIXME: adds extra \s before closing `>` in opening tag, and another after class names + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Sample text.

`); + }); +}); + +// MUSTACHE INJECTION SYNTAX + +describe('Injection: When an injection tag follows an element', ()=>{ + // FIXME: Most of these fail because injections currently replace attributes, rather than append to. Or just minor extra whitespace issues. + describe('and that element is an inline-block', ()=>{ + it.failing('Renders a span "text" with no injection', function() { + const source = '{{ text}}{}'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a span "text" with injected Class name', function() { + const source = '{{ text}}{ClassName}'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a span "text" with injected style', function() { + const source = '{{ text}}{color:red}'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders a span "text" with two injected styles', function() { + const source = '{{ text}}{color:red,background:blue}'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + }); + + it.failing('Renders an emphasis element with injected Class name', function() { + const source = '*emphasis*{big}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

emphasis

'); + }); + + it.failing('Renders a code element with injected style', function() { + const source = '`code`{background:gray}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

code

'); + }); + + it.failing('Renders an image element with injected style', function() { + const source = '![alt text](http://i.imgur.com/hMna6G0.png){position:absolute}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

homebrew mug

'); + }); + + it.failing('Renders an element modified by only the first of two consecutive injections', function() { + const source = '{{ text}}{color:red}{background:blue}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

text{background:blue}

'); + }); + }); + + describe('and that element is a block', ()=>{ + it.failing('renders a div "text" with no injection', function() { + const source = '{{\ntext\n}}\n{}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

text

'); + }); + + it.failing('renders a div "text" with injected Class name', function() { + const source = '{{\ntext\n}}\n{ClassName}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

text

'); + }); + + it.failing('renders a div "text" with injected style', function() { + const source = '{{\ntext\n}}\n{color:red}'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

text

'); + }); + + it.failing('renders a div "text" with two injected styles', function() { + const source = dedent`{{ + text + }} + {color:red,background:blue}`; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

text

'); + }); + + it.failing('renders an h2 header "text" with injected class name', function() { + const source = dedent`## text + {ClassName}`; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

text

'); + }); + + it.failing('renders a table with injected class name', function() { + const source = dedent`| Experience Points | Level | + |:------------------|:-----:| + | 0 | 1 | + | 300 | 2 | + + {ClassName}`; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
Experience PointsLevel
01
3002
`); + }); + + // it('renders a list with with a style injected into the