0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-29 04:42:41 +00:00

Merge branch 'master' into addMetadataToShare-#1679

This commit is contained in:
G.Ambatte
2023-04-08 17:14:39 +12:00
committed by GitHub
12 changed files with 661 additions and 404 deletions

View File

@@ -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

View File

@@ -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', {

View File

@@ -82,4 +82,4 @@ const ErrorNavItem = createClass({
}
});
module.exports = ErrorNavItem;
module.exports = ErrorNavItem;

View File

@@ -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;
}
}
}
.confirm {
width : 48%;
margin : 1px;
padding : 5px;
background-color : #333;
display : inline-block;
color : white;
.animate(background-color);
&:hover{
background-color : teal;
}
}
}

View File

@@ -254,6 +254,15 @@ const EditPage = createClass({
</div>
</div>
}
{this.state.alertTrashedGoogleBrew &&
<div className='errorContainer' onClick={this.closeAlerts}>
This brew is currently in your Trash folder on Google Drive!<br />If you want to keep it, make sure to move it before it is deleted permanently!<br />
<div className='confirm'>
OK
</div>
</div>
}
</Nav.item>;
},
@@ -335,16 +344,6 @@ const EditPage = createClass({
const shareLink = this.processShareId();
return <Navbar>
{this.state.alertTrashedGoogleBrew &&
<div className='errorContainer' onClick={this.closeAlerts}>
This brew is currently in your Trash folder on Google Drive!<br />If you want to keep it, make sure to move it before it is deleted permanently!<br />
<div className='confirm'>
OK
</div>
</div>
}
<Nav.section>
<Nav.item className='brewTitle'>{this.state.brew.title}</Nav.item>
</Nav.section>

316
package-lock.json generated
View File

@@ -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": {

View File

@@ -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"
}
}

View File

@@ -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' };

View File

@@ -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']);

View File

@@ -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';

View File

@@ -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('<span class="inline-block ">text</span>');
});
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('<span class="inline-block ">this is a text</span>');
});
test('Renders an empty mustache span', function() {
const source = '{{}}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block "></span>');
});
test('Renders a mustache span with just a space', function() {
const source = '{{ }}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block "></span>');
});
test('Renders a mustache span with a few spaces only', function() {
const source = '{{ }}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block "></span>');
});
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('<span class="inline-block my-class" >text</span>');
});
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('<span class="inline-block my-class my-class2" >text</span>');
});
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('<span class="inline-block my-class" >this is a text</span>');
});
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('<span class="inline-block " id="my-span" >text</span>');
});
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('<span class="inline-block " id="my-span" >text</span>');
});
test('Renders a mustache span with text and css property', function() {
const source = '{{color:red text}}';
const rendered = Markdown.render(source);
expect(rendered).toBe('<span class="inline-block " style="color:red;">text</span>');
});
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('<span class="inline-block " style="color:red; padding:5px;">text</span>');
});
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('<span class="inline-block " style="font:trebuchet ms;">text</span>');
});
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('<span class="inline-block " style="font:trebuchet ms; padding:5px 10px;">text</span>');
});
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('<span class="inline-block " style="font:trebuchet ms;">text “with quotes”</span>');
});
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('<span class="inline-block pen" id="author" style="color:orange; font-family:trebuchet ms;">text</span>');
});
// 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.

View File

@@ -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('<span class="inline-block">text</span>');
});
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('<span class="inline-block">this is a text</span>');
});
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('<span class="inline-block"></span>');
});
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('<span class="inline-block"></span>');
});
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('<span class="inline-block"></span>');
});
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('<span class="inline-block my-class">text</span>');
});
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('<span class="inline-block my-class my-class2">text</span>');
});
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('<span class="inline-block my-class">this is a text</span>');
});
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('<span class="inline-block" id="my-span">text</span>');
});
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('<span class="inline-block" id="my-span">text</span>');
});
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('<span class="inline-block" style="color:red;">text</span>');
});
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('<span class="inline-block" style="color:red; padding:5px;">text</span>');
});
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('<span class="inline-block" style="font-family:trebuchet ms;">text</span>');
});
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('<span class="inline-block" style="font-family:trebuchet ms; padding:5px 10px;">text</span>');
});
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('<span class="inline-block" style="font-family:trebuchet ms;">text “with quotes”</span>');
});
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('<span class="inline-block pen" id="author" style="color:orange; font-family:trebuchet ms;">text</span>');
});
});
// 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(`<div class="block"><p>text</p></div>`);
});
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(`<div class="block"></div>`);
});
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(`<p>{{}}</p>`);
});
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(`<div class="block cat"></div>`);
});
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(`<div class="block cat"><p>Sample text.</p></div>`);
});
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(`<div class="block cat dog"><p>Sample text.</p></div>`);
});
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(`<div class="block" style="color:red;"><p>Sample text.</p></div>`);
});
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(`<div class="block cat" style="color:red;"><p>Sample text.</p></div>`);
});
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(`<div class="block cat" id="dog" style="color:red;"><p>Sample text.</p></div>`);
});
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(`<div class="block" id="cat"><p>Sample text.</p></div>`);
});
});
// 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('<span class="inline-block">text</span>');
});
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('<span class="inline-block ClassName">text</span>');
});
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('<span class="inline-block" style="color:red;">text</span>');
});
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('<span class="inline-block" style="color:red; background:blue;">text</span>');
});
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('<p><em class="big">emphasis</em></p>');
});
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('<p><code style="background:gray;">code</code></p>');
});
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('<p><img src="http://i.imgur.com/hMna6G0.png" alt="homebrew mug" style="position:absolute;"></p>');
});
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('<p><span class="inline-block" style="color:red;">text</span>{background:blue}</p>');
});
});
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('<div class="block"><p>text</p></div>');
});
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('<div class="block ClassName"><p>text</p></div>');
});
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('<div class="block" style="color:red;"><p>text</p></div>');
});
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('<div class="block" style="color:red; background:blue;"><p>text</p></div>');
});
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('<h2 class="ClassName">text</h2>');
});
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(`<table class="ClassName"><thead><tr><th align=left>Experience Points</th><th align=center>Level</th></tr></thead><tbody><tr><td align=left>0</td><td align=center>1</td></tr><tr><td align=left>300</td><td align=center>2</td></tr></tbody></table>`);
});
// it('renders a list with with a style injected into the <ul> tag', function() {
// const source = dedent`- Cursed Ritual of Bad Hair
// - Eliminate Vindictiveness in Gym Teacher
// - Ultimate Rite of the Confetti Angel
// - Dark Chant of the Dentists
// - Divine Spell of Crossdressing
// {color:red}`;
// const rendered = Markdown.render(source).trimReturns();
// expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`...`); // FIXME: expect this to be injected into <ul>? Currently injects into last <li>
// });
it.failing('renders an h2 header "text" with injected class name, and "secondInjection" as regular text on the next line.', function() {
const source = dedent`## text
{ClassName}
{secondInjection}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<h2 class="ClassName">text</h2><p>{secondInjection}</p>');
});
it.failing('renders a div nested into another div, the inner with class=innerDiv and the other class=outerDiv', function() {
const source = dedent`{{
outer text
{{
inner text
}}
{innerDiv}
}}
{outerDiv}`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block outerDiv"><p>outer text</p><div class="block innerDiv"><p>inner text</p></div></div>');
});
});
});
// 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.