gscan 4.29.0 → 4.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/tpl/error.hbs +1 -1
- package/app/tpl/index.hbs +2 -2
- package/app/tpl/layouts/default.hbs +8 -8
- package/bin/cli.js +2 -2
- package/lib/ast-linter/rules/index.js +5 -1
- package/lib/ast-linter/rules/internal/scope.js +14 -0
- package/lib/ast-linter/rules/lint-no-price-data-currency-context.js +26 -0
- package/lib/ast-linter/rules/lint-no-price-data-currency-global.js +26 -0
- package/lib/ast-linter/rules/lint-no-price-data-monthly-yearly.js +20 -0
- package/lib/ast-linter/rules/lint-no-tier-benefit-as-object.js +30 -0
- package/lib/ast-linter/rules/{lint-no-price-data-helper.js → lint-no-tier-price-as-object.js} +6 -3
- package/lib/checks/010-package-json.js +9 -1
- package/lib/format.js +1 -24
- package/lib/specs/canary.js +56 -18
- package/lib/specs/v1.js +40 -40
- package/lib/specs/v2.js +31 -29
- package/lib/specs/v3.js +6 -5
- package/lib/specs/v4.js +18 -16
- package/lib/utils/score-calculator.js +40 -0
- package/lib/utils/versions.json +1 -1
- package/package.json +4 -4
package/app/tpl/error.hbs
CHANGED
package/app/tpl/index.hbs
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
<span class="gh-input-icon select-arrow">{{> icon-arrow-up}}</span>
|
|
23
23
|
<span class="gh-input-icon select-arrow active">{{> icon-arrow-down}}</span>
|
|
24
24
|
<select class="gh-input gh-select" name="version" id="version">
|
|
25
|
-
<option value="v5">{{ghostVersions.v5.major}}</option>
|
|
26
|
-
<option value="v4"
|
|
25
|
+
<option value="v5" selected>{{ghostVersions.v5.major}}</option>
|
|
26
|
+
<option value="v4">{{ghostVersions.v4.major}}</option>
|
|
27
27
|
<option value="v3">{{ghostVersions.v3.major}}</option>
|
|
28
28
|
<option value="v2">{{ghostVersions.v2.major}}</option>
|
|
29
29
|
<option value="v1">{{ghostVersions.v1.major}}</option>
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
|
|
58
58
|
</div>
|
|
59
59
|
<div class="gh-navbar-right">
|
|
60
|
-
<a class="gh-navbar-item" href="https://ghost.org/docs/
|
|
61
|
-
<a class="gh-navbar-btn gh-btn" href="https://ghost.org"><span>Ghost.org</span></a>
|
|
60
|
+
<a class="gh-navbar-item" href="https://ghost.org/docs/themes/" target="blank" rel="noopener">Theme Docs</a>
|
|
61
|
+
<a class="gh-navbar-btn gh-btn" href="https://ghost.org/"><span>Ghost.org</span></a>
|
|
62
62
|
</div>
|
|
63
63
|
</nav>
|
|
64
64
|
</header>
|
|
@@ -99,8 +99,8 @@
|
|
|
99
99
|
</nav>
|
|
100
100
|
<div class="gh-mobilemenu">
|
|
101
101
|
<a class="gh-navbar-item" href="https://gscan.ghost.org">GScan</a>
|
|
102
|
-
<a class="gh-navbar-item" href="https://ghost.org/docs/
|
|
103
|
-
<a class="gh-navbar-item" href="https://ghost.org">Ghost.org</a>
|
|
102
|
+
<a class="gh-navbar-item" href="https://ghost.org/docs/themes/">Theme Docs</a>
|
|
103
|
+
<a class="gh-navbar-item" href="https://ghost.org/">Ghost.org</a>
|
|
104
104
|
</div>
|
|
105
105
|
</header>
|
|
106
106
|
|
|
@@ -112,9 +112,9 @@
|
|
|
112
112
|
|
|
113
113
|
<footer class="gh-foot">
|
|
114
114
|
<div class="gh-foot-support inner">
|
|
115
|
-
<div class="gh-support-email" href="https://ghost.org/pricing">
|
|
115
|
+
<div class="gh-support-email" href="https://ghost.org/pricing/">
|
|
116
116
|
<h4>Ready to upgrade to the best?</h4>
|
|
117
|
-
<p>Spend less time running your servers and more time running your site. <strong><a href="https://ghost.org/pricing">Ghost(Pro)</a></strong>
|
|
117
|
+
<p>Spend less time running your servers and more time running your site. <strong><a href="https://ghost.org/pricing/">Ghost(Pro)</a></strong>
|
|
118
118
|
has got you covered</p>
|
|
119
119
|
</div>
|
|
120
120
|
<div class="gh-support-slack">
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
</div>
|
|
126
126
|
<div class="gh-foot-content inner">
|
|
127
127
|
<nav class="gh-foot-min-nav">
|
|
128
|
-
<a class="gh-foot-min-item gh-foot-min-logo" href="https://ghost.org">
|
|
128
|
+
<a class="gh-foot-min-item gh-foot-min-logo" href="https://ghost.org/">
|
|
129
129
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 294" preserveAspectRatio="xMidYMid meet" class="ghost-orb-logo-wh">
|
|
130
130
|
<title>Ghost Logo</title>
|
|
131
131
|
<style>
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
<a class="gh-foot-min-item" href="https://twitter.com/ghost">@Ghost</a>
|
|
155
155
|
</nav>
|
|
156
156
|
<div class="gh-foot-min-back">
|
|
157
|
-
<a class="gh-foot-min-item" href="https://ghost.org">Back to Ghost</a>
|
|
157
|
+
<a class="gh-foot-min-item" href="https://ghost.org/">Back to Ghost</a>
|
|
158
158
|
</div>
|
|
159
159
|
</div>
|
|
160
160
|
</footer>
|
package/bin/cli.js
CHANGED
|
@@ -136,7 +136,7 @@ function outputResult(result, options) {
|
|
|
136
136
|
let message = failure.ref;
|
|
137
137
|
|
|
138
138
|
if (failure.message) {
|
|
139
|
-
message +=
|
|
139
|
+
message += ` - ${failure.message}`;
|
|
140
140
|
}
|
|
141
141
|
ui.log(message);
|
|
142
142
|
});
|
|
@@ -221,7 +221,7 @@ function outputResults(theme, options) {
|
|
|
221
221
|
_.each(theme.results.recommendation, rule => outputResult(rule, options));
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
ui.log(`\nGet more help at ${chalk.cyan.underline('https://ghost.org/docs/
|
|
224
|
+
ui.log(`\nGet more help at ${chalk.cyan.underline('https://ghost.org/docs/themes/')}`);
|
|
225
225
|
ui.log(`You can also check theme compatibility at ${chalk.cyan.underline('https://gscan.ghost.org/')}`);
|
|
226
226
|
|
|
227
227
|
// The CLI feature is mainly used to run gscan programatically in tests within themes.
|
|
@@ -7,7 +7,11 @@ module.exports = {
|
|
|
7
7
|
'GS090-NO-PRODUCT-DATA-HELPER': require('./lint-no-product-data-helper'),
|
|
8
8
|
'GS090-NO-PRODUCTS-DATA-HELPER': require('./lint-no-products-data-helper'),
|
|
9
9
|
'GS090-NO-MEMBER-PRODUCTS-DATA-HELPER': require('./lint-no-member-products-data-helper'),
|
|
10
|
-
'GS090-NO-PRICE-
|
|
10
|
+
'GS090-NO-TIER-PRICE-AS-OBJECT': require('./lint-no-tier-price-as-object'),
|
|
11
|
+
'GS090-NO-TIER-BENEFIT-AS-OBJECT': require('./lint-no-tier-benefit-as-object'),
|
|
12
|
+
'GS090-NO-PRICE-DATA-CURRENCY-GLOBAL': require('./lint-no-price-data-currency-global'),
|
|
13
|
+
'GS090-NO-PRICE-DATA-CURRENCY-CONTEXT': require('./lint-no-price-data-currency-context'),
|
|
14
|
+
'GS090-NO-PRICE-DATA-MONTHLY-YEARLY': require('./lint-no-price-data-monthly-yearly'),
|
|
11
15
|
'no-multi-param-conditionals': require('./lint-no-multi-param-conditionals'),
|
|
12
16
|
'no-nested-async-helpers': require('./lint-no-nested-async-helpers'),
|
|
13
17
|
'no-prev-next-post-outside-post-context': require('./lint-no-prev-next-post-outside-post-context'),
|
|
@@ -204,6 +204,20 @@ class Scope {
|
|
|
204
204
|
return found;
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
getParentContextNode(context) {
|
|
208
|
+
let matchedFrame = null;
|
|
209
|
+
|
|
210
|
+
if (this.frames && this.frames.length) {
|
|
211
|
+
matchedFrame = this.frames.find((frame) => {
|
|
212
|
+
if (frame.nodeName === context) {
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return matchedFrame && matchedFrame.node;
|
|
219
|
+
}
|
|
220
|
+
|
|
207
221
|
isLocal(node) {
|
|
208
222
|
// @foo MustacheStatements are referencing globals rather than locals
|
|
209
223
|
if (node.type === 'MustacheStatement' && node.path.data) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const Rule = require('./base');
|
|
2
|
+
const _ = require('lodash');
|
|
3
|
+
|
|
4
|
+
module.exports = class NoPriceDataCurrencyContext extends Rule {
|
|
5
|
+
_findPriceData(node) {
|
|
6
|
+
if (node.data && node.parts && node.parts.length === 2 && node.parts[0] === 'price' && node.parts[1] === 'currency') {
|
|
7
|
+
const foreachNode = this.scope.getParentContextNode('foreach');
|
|
8
|
+
const foreachObject = _.get(foreachNode, 'params[0].original');
|
|
9
|
+
|
|
10
|
+
if (['@member.subscriptions', 'tiers'].includes(foreachObject)) {
|
|
11
|
+
this.log(({
|
|
12
|
+
message: `{{@price.currency}} should be replaced with {{currency}}`,
|
|
13
|
+
line: node.loc && node.loc.start.line,
|
|
14
|
+
column: node.loc && node.loc.start.column,
|
|
15
|
+
source: this.sourceForNode(node)
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
visitor() {
|
|
22
|
+
return {
|
|
23
|
+
PathExpression: this._findPriceData.bind(this)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const Rule = require('./base');
|
|
2
|
+
const _ = require('lodash');
|
|
3
|
+
|
|
4
|
+
module.exports = class NoPriceDataCurrencyGlobal extends Rule {
|
|
5
|
+
_findPriceData(node) {
|
|
6
|
+
if (node.data && node.parts && node.parts.length === 2 && node.parts[0] === 'price' && node.parts[1] === 'currency') {
|
|
7
|
+
const foreachNode = this.scope.getParentContextNode('foreach');
|
|
8
|
+
const foreachObject = _.get(foreachNode, 'params[0].original');
|
|
9
|
+
|
|
10
|
+
if (!['@member.subscriptions', 'tiers'].includes(foreachObject)) {
|
|
11
|
+
this.log(({
|
|
12
|
+
message: `{{@price.currency}} should be replaced with {{currency}} and a context`,
|
|
13
|
+
line: node.loc && node.loc.start.line,
|
|
14
|
+
column: node.loc && node.loc.start.column,
|
|
15
|
+
source: this.sourceForNode(node)
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
visitor() {
|
|
22
|
+
return {
|
|
23
|
+
PathExpression: this._findPriceData.bind(this)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const Rule = require('./base');
|
|
2
|
+
|
|
3
|
+
module.exports = class NoPriceDataMonthlyYearly extends Rule {
|
|
4
|
+
_findPriceData(node) {
|
|
5
|
+
if (node.data && node.parts && node.parts.length === 2 && node.parts[0] === 'price' && ['monthly', 'yearly'].includes(node.parts[1])) {
|
|
6
|
+
this.log(({
|
|
7
|
+
message: `{{@price.monthly}} and {{@price.yearly}} should be replaced with {{#get "tiers"}}`,
|
|
8
|
+
line: node.loc && node.loc.start.line,
|
|
9
|
+
column: node.loc && node.loc.start.column,
|
|
10
|
+
source: this.sourceForNode(node)
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
visitor() {
|
|
16
|
+
return {
|
|
17
|
+
PathExpression: this._findPriceData.bind(this)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const Rule = require('./base');
|
|
2
|
+
const {getNodeName, logNode} = require('../helpers');
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
5
|
+
module.exports = class NoTierBenefitAsObject extends Rule {
|
|
6
|
+
_checkForHelperName(node) {
|
|
7
|
+
const nodeName = getNodeName(node);
|
|
8
|
+
const isMatchingHelper = (nodeName.includes('name'));
|
|
9
|
+
const foreachNode = this.scope.getParentContextNode('foreach');
|
|
10
|
+
const getNode = this.scope.getParentContextNode('get');
|
|
11
|
+
|
|
12
|
+
const hasForeachBenefits = _.get(foreachNode, 'params[0].original') === 'benefits';
|
|
13
|
+
const hasGetTiers = _.get(getNode, 'params[0].original') === 'tiers';
|
|
14
|
+
|
|
15
|
+
if (hasForeachBenefits && hasGetTiers && isMatchingHelper) {
|
|
16
|
+
this.log({
|
|
17
|
+
message: `${logNode(node)} should not be used`,
|
|
18
|
+
line: node.loc && node.loc.start.line,
|
|
19
|
+
column: node.loc && node.loc.start.column,
|
|
20
|
+
source: this.sourceForNode(node)
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
visitor() {
|
|
26
|
+
return {
|
|
27
|
+
MustacheStatement: this._checkForHelperName.bind(this)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
package/lib/ast-linter/rules/{lint-no-price-data-helper.js → lint-no-tier-price-as-object.js}
RENAMED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
1
2
|
const Rule = require('./base');
|
|
2
3
|
const {getNodeName, logNode} = require('../helpers');
|
|
3
4
|
|
|
4
|
-
module.exports = class
|
|
5
|
+
module.exports = class NoMonthlyYearlyPriceObjects extends Rule {
|
|
5
6
|
_checkForHelperName(node) {
|
|
6
7
|
const nodeName = getNodeName(node);
|
|
7
|
-
const isMatchingHelper = (nodeName.
|
|
8
|
+
const isMatchingHelper = (nodeName.includes('monthly_price.')) || (nodeName.includes('yearly_price.'));
|
|
9
|
+
const getNode = this.scope.getParentContextNode('get');
|
|
10
|
+
const hasGetTiers = _.get(getNode, 'params[0].original') === 'tiers';
|
|
8
11
|
|
|
9
|
-
if (isMatchingHelper) {
|
|
12
|
+
if (isMatchingHelper && hasGetTiers) {
|
|
10
13
|
this.log({
|
|
11
14
|
message: `${logNode(node)} should not be used`,
|
|
12
15
|
line: node.loc && node.loc.start.line,
|
|
@@ -55,7 +55,10 @@ const v4PackageJSONValidationRules = _.extend({},
|
|
|
55
55
|
);
|
|
56
56
|
|
|
57
57
|
const canaryPackageJSONConditionalRules = {};
|
|
58
|
-
const canaryPackageJSONValidationRules = _.extend({}
|
|
58
|
+
const canaryPackageJSONValidationRules = _.extend({},
|
|
59
|
+
{isNotPresentCardAssets: 'GS010-PJ-GHOST-CARD-ASSETS-NOT-PRESENT'},
|
|
60
|
+
canaryPackageJSONConditionalRules
|
|
61
|
+
);
|
|
59
62
|
|
|
60
63
|
_private.validatePackageJSONFields = function validatePackageJSONFields(packageJSON, theme, packageJSONValidationRules) {
|
|
61
64
|
let failed = [];
|
|
@@ -138,6 +141,11 @@ _private.validatePackageJSONFields = function validatePackageJSONFields(packageJ
|
|
|
138
141
|
}
|
|
139
142
|
}
|
|
140
143
|
|
|
144
|
+
// @TODO: validate that the card_assets config is valid
|
|
145
|
+
if (!packageJSON.config || (_.isEmpty(packageJSON.config.card_assets) && !_.isBoolean(packageJSON.config.card_assets))) {
|
|
146
|
+
markFailed('isNotPresentCardAssets');
|
|
147
|
+
}
|
|
148
|
+
|
|
141
149
|
if (packageJSON.config && packageJSON.config.custom) {
|
|
142
150
|
const customSettingsKeys = Object.keys(packageJSON.config.custom);
|
|
143
151
|
|
package/lib/format.js
CHANGED
|
@@ -1,30 +1,7 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
2
|
const spec = require('./specs');
|
|
3
|
-
const levelWeights = {
|
|
4
|
-
error: 10,
|
|
5
|
-
warning: 3,
|
|
6
|
-
recommendation: 1
|
|
7
|
-
};
|
|
8
3
|
const versions = require('./utils').versions;
|
|
9
|
-
|
|
10
|
-
const calcScore = function calcScore(results, stats) {
|
|
11
|
-
var maxScore, actualScore, balancedScore;
|
|
12
|
-
|
|
13
|
-
maxScore = _.reduce(levelWeights, function (max, weight, level) {
|
|
14
|
-
return max + (weight * stats[level]);
|
|
15
|
-
}, 0);
|
|
16
|
-
|
|
17
|
-
actualScore = _.reduce(levelWeights, function (max, weight, level) {
|
|
18
|
-
return max - (weight * _.size(results[level]));
|
|
19
|
-
}, maxScore);
|
|
20
|
-
|
|
21
|
-
balancedScore = _.ceil((100 / maxScore) * actualScore);
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
value: balancedScore,
|
|
25
|
-
level: _.size(results.error) > 0 ? 'error' : balancedScore < 60 ? 'warning' : 'passing'
|
|
26
|
-
};
|
|
27
|
-
};
|
|
4
|
+
const calcScore = require('./utils/score-calculator');
|
|
28
5
|
|
|
29
6
|
const formatCLI = (theme) => {
|
|
30
7
|
_.each(theme.results, (results) => {
|
package/lib/specs/canary.js
CHANGED
|
@@ -21,9 +21,15 @@ let rules = {
|
|
|
21
21
|
// New rules
|
|
22
22
|
'GS010-PJ-GHOST-API-PRESENT': {
|
|
23
23
|
level: 'warning',
|
|
24
|
-
rule: 'Remove <code>"engines.ghost-api"</code> from <code>package.json</code
|
|
24
|
+
rule: 'Remove <code>"engines.ghost-api"</code> from <code>package.json</code>',
|
|
25
25
|
details: oneLineTrim`The <code>"ghost-api"</code> version is no longer used and can be removed.<br>
|
|
26
|
-
Find more information about the <code>package.json</code> file <a href="${docsBaseUrl}packagejson
|
|
26
|
+
Find more information about the <code>package.json</code> file <a href="${docsBaseUrl}structure/#packagejson" target=_blank>here</a>.`
|
|
27
|
+
},
|
|
28
|
+
'GS010-PJ-GHOST-CARD-ASSETS-NOT-PRESENT': {
|
|
29
|
+
level: 'warning',
|
|
30
|
+
rule: '<code>"card_assets"</code> will default to <code>true</code> in <code>package.json</code>',
|
|
31
|
+
details: oneLineTrim`The <code>"card_assets"</code> property is enabled by default if not explicitly set.<br>
|
|
32
|
+
Find more information about the <code>card_assets</code> property <a href="${docsBaseUrl}content/#editor-cards" target=_blank>here</a>.`
|
|
27
33
|
},
|
|
28
34
|
'GS090-NO-AUTHOR-HELPER-IN-POST-CONTEXT': {
|
|
29
35
|
level: 'error',
|
|
@@ -69,14 +75,46 @@ let rules = {
|
|
|
69
75
|
Find more information about the <code>{{@member.subscriptions}}</code> property <a href="${docsBaseUrl}members/#member-subscriptions" target=_blank>here</a>.`,
|
|
70
76
|
helper: '{{@member.products}}'
|
|
71
77
|
},
|
|
72
|
-
'GS090-NO-PRICE-DATA-
|
|
78
|
+
'GS090-NO-PRICE-DATA-CURRENCY-GLOBAL': {
|
|
79
|
+
level: 'error',
|
|
80
|
+
fatal: true,
|
|
81
|
+
rule: 'Replace <code>@price.currency</code> with <code>{{#get "tiers"}}</code> and <code>{{currency}}</code> or <code>{{#foreach @member.subscriptions}}</code> and <code>{{plan.currency}}</code>',
|
|
82
|
+
details: oneLineTrim`There is no longer a global <code>@price</code> object. You need to use either <code>{{#get "tiers"}}</code> to fetch all tiers and use the <code>{{currency}}</code> property of a tier<br>
|
|
83
|
+
or use <code>{{#foreach @member.subscriptions}}</code> to fetch an individual member's subscriptions, and use the <code>{{plan.currency}}</code> property from the subscription.<br>
|
|
84
|
+
Find more information about the <code>{{price}}</code> helper <a href="${docsBaseUrl}members/price/" target=_blank>here</a>.`
|
|
85
|
+
},
|
|
86
|
+
'GS090-NO-PRICE-DATA-CURRENCY-CONTEXT': {
|
|
87
|
+
level: 'error',
|
|
88
|
+
fatal: true,
|
|
89
|
+
rule: 'Replace <code>{{@price.currency}}</code> with <code>{{currency}}</code> or <code>{{plan.currency}}</code>',
|
|
90
|
+
details: oneLineTrim`There is no longer a global <code>@price</code> object. Instead the <code>{{currency}}</code> property can be used inside <code>{{#get "tiers"}}</code><br>
|
|
91
|
+
or <code>{{plan.currency}}</code> can be used inside <code>{{#foreach @member.subscriptions}}</code><br>
|
|
92
|
+
Find more information about the <code>{{price}}</code> helper <a href="${docsBaseUrl}members/price/" target=_blank>here</a>.`
|
|
93
|
+
},
|
|
94
|
+
'GS090-NO-PRICE-DATA-MONTHLY-YEARLY': {
|
|
95
|
+
level: 'error',
|
|
96
|
+
fatal: true,
|
|
97
|
+
rule: 'Replace <code>{{@price.monthly}}</code> and <code>{{@price.yearly}}</code> with <code>{{#get "tiers"}}</code> and <code>{{monthly_price}}</code> or <code>{{yearly_price}}</code>',
|
|
98
|
+
details: oneLineTrim`There is no longer a global <code>@price</code> object. You need to use <code>{{#get "tiers"}}</code> to fetch all the tiers and get access to the <code>{{monthly_price}}</code> or <code>{{yearly_price}}</code> for each tier<br>
|
|
99
|
+
Find more information about the <code>{{price}}</code> helper <a href="${docsBaseUrl}helpers/price/" target=_blank>here</a>.`
|
|
100
|
+
},
|
|
101
|
+
'GS090-NO-TIER-PRICE-AS-OBJECT': {
|
|
102
|
+
level: 'error',
|
|
103
|
+
fatal: true,
|
|
104
|
+
rule: 'Remove usage of <code>{{monthly_price.*}}</code> and <code>{{yearly_price.*}}.</code>',
|
|
105
|
+
details: oneLineTrim`The usage of <code>{{monthly_price.*}}</code> and <code>{{yearly_price.*}} is no longer supported.</code><br>
|
|
106
|
+
${tierDesc}<br>
|
|
107
|
+
Find more information about the <code>{{#get "tiers"}}</code> <a href="${docsBaseUrl}helpers/tiers/" target=_blank>here</a>.`,
|
|
108
|
+
helper: '{{#get "tiers"}}'
|
|
109
|
+
},
|
|
110
|
+
'GS090-NO-TIER-BENEFIT-AS-OBJECT': {
|
|
73
111
|
level: 'error',
|
|
74
112
|
fatal: true,
|
|
75
|
-
rule: '
|
|
76
|
-
details: oneLineTrim`The <code>{{
|
|
113
|
+
rule: 'Remove usage of <code>{{name}}</code> for tier benefits.</code>',
|
|
114
|
+
details: oneLineTrim`The usage of <code>{{name}}</code> for tier benefits is no longer supported.</code><br>
|
|
77
115
|
${tierDesc}<br>
|
|
78
|
-
Find more information about the <code>{{
|
|
79
|
-
helper: '{{
|
|
116
|
+
Find more information about the <code>{{#get "tiers"}}</code> <a href="${docsBaseUrl}helpers/tiers/" target=_blank>here</a>.`,
|
|
117
|
+
helper: '{{#get "tiers"}}'
|
|
80
118
|
},
|
|
81
119
|
|
|
82
120
|
// Updated v1 & v2 rules
|
|
@@ -414,7 +452,7 @@ let rules = {
|
|
|
414
452
|
rule: 'Replace <code>{{post.author_id}}</code> code with <code>{{post.primary_author.id}}</code>',
|
|
415
453
|
details: oneLineTrim`The <code>{{post.author_id}}</code> attribute in post context was removed<br>
|
|
416
454
|
Instead of <code>{{post.author_id}}</code> you need to use <code>{{post.primary_author.id}}</code>.<br>
|
|
417
|
-
Find more information about the object attributes of <code>post</code> <a href="${docsBaseUrl}
|
|
455
|
+
Find more information about the object attributes of <code>post</code> <a href="${docsBaseUrl}contexts/post/#post-object-attributes" target=_blank>here</a>.`,
|
|
418
456
|
regex: /{{\s*?post\.author_id\s*?}}/g,
|
|
419
457
|
helper: '{{post.author_id}}'
|
|
420
458
|
},
|
|
@@ -447,7 +485,7 @@ let rules = {
|
|
|
447
485
|
details: oneLineTrim`The <code>cover</code> attribute was replaced with <code>cover_image</code>.<br>
|
|
448
486
|
Instead of <code>{{author.cover}}</code> you need to use
|
|
449
487
|
<code>{{primary_author.cover_image}}</code> or <code>{{authors.[#].cover_image}}</code>.<br>
|
|
450
|
-
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}
|
|
488
|
+
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}contexts/author/#author-object-attributes" target=_blank>here</a>.`,
|
|
451
489
|
regex: /{{\s*?author\.cover\s*?}}/g,
|
|
452
490
|
helper: '{{author.cover}}'
|
|
453
491
|
},
|
|
@@ -458,7 +496,7 @@ let rules = {
|
|
|
458
496
|
details: oneLineTrim`The <code>image</code> attribute was replaced with <code>profile_image</code>.<br>
|
|
459
497
|
Instead of <code>{{author.image}}</code>, you need to use
|
|
460
498
|
<code>{{primary_author.profile_image}}</code> or <code>{{authors.[#].profile_image}}</code>.<br>
|
|
461
|
-
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}
|
|
499
|
+
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}contexts/author/#author-object-attributes" target=_blank>here</a>.`,
|
|
462
500
|
regex: /{{\s*?author\.image\s*?}}/g,
|
|
463
501
|
helper: '{{author.image}}'
|
|
464
502
|
},
|
|
@@ -469,7 +507,7 @@ let rules = {
|
|
|
469
507
|
details: oneLineTrim`The <code>cover</code> attribute was replaced with <code>cover_image</code>.<br>
|
|
470
508
|
Instead of <code>{{post.author.cover}}</code>, you need to use
|
|
471
509
|
<code>{{post.primary_author.cover_image}}</code> or <code>{{post.authors.[#].cover_image}}</code>.<br>
|
|
472
|
-
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}
|
|
510
|
+
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}contexts/author/#author-object-attributes" target=_blank>here</a>.`,
|
|
473
511
|
regex: /{{\s*?post\.author\.cover\s*?}}/g,
|
|
474
512
|
helper: '{{post.author.cover}}'
|
|
475
513
|
},
|
|
@@ -526,7 +564,7 @@ let rules = {
|
|
|
526
564
|
details: oneLineTrim`The <code>image</code> attribute was replaced with <code>profile_image</code>.<br>
|
|
527
565
|
Instead of <code>{{post.author.image}}</code>, you need to use
|
|
528
566
|
<code>{{post.primary_author.profile_image}}</code> or <code>{{post.authors.[#].profile_image}}</code>.<br>
|
|
529
|
-
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}
|
|
567
|
+
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}contexts/author/#author-object-attributes" target=_blank>here</a>.`,
|
|
530
568
|
regex: /{{\s*?post\.author\.image\s*?}}/g,
|
|
531
569
|
helper: '{{post.author.image}}'
|
|
532
570
|
},
|
|
@@ -561,7 +599,7 @@ let rules = {
|
|
|
561
599
|
details: oneLineTrim`The <code>cover</code> attribute was replaced with <code>cover_image</code>.<br>
|
|
562
600
|
Instead of <code>{{#if author.cover}}</code>, you need to use
|
|
563
601
|
<code>{{#if primary_author.cover_image}}</code> or <code>{{#if authors.[#].cover_image}}</code>.<br>
|
|
564
|
-
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}
|
|
602
|
+
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}contexts/author/#author-object-attributes" target=_blank>here</a>.`,
|
|
565
603
|
regex: /{{\s*?#if\s*?author\.cover\s*?}}/g,
|
|
566
604
|
helper: '{{#if author.cover}}'
|
|
567
605
|
},
|
|
@@ -572,7 +610,7 @@ let rules = {
|
|
|
572
610
|
details: oneLineTrim`The <code>image</code> attribute was replaced with <code>profile_image</code>.<br>
|
|
573
611
|
Instead of <code>{{#if author.image}}</code>, you need to use
|
|
574
612
|
<code>{{#if primary_author.profile_image}}</code> or <code>{{#if authors.[#].profile_image}}</code>.<br>
|
|
575
|
-
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}
|
|
613
|
+
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}contexts/author/#author-object-attributes" target=_blank>here</a>.`,
|
|
576
614
|
regex: /{{\s*?#if\s*?author\.image\s*?}}/g,
|
|
577
615
|
helper: '{{#if author.image}}'
|
|
578
616
|
},
|
|
@@ -583,7 +621,7 @@ let rules = {
|
|
|
583
621
|
details: oneLineTrim`The <code>cover</code> attribute was replaced with <code>cover_image</code>.<br>
|
|
584
622
|
Instead of <code>{{#if post.author.cover}}</code>, you need to use
|
|
585
623
|
<code>{{#if post.primary_author.cover_image}}</code> or <code>{{#if post.authors.[#].cover_image}}</code>.<br>
|
|
586
|
-
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}
|
|
624
|
+
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}contexts/author/#author-object-attributes" target=_blank>here</a>.`,
|
|
587
625
|
regex: /{{\s*?#if\s*?post\.author\.cover\s*?}}/g,
|
|
588
626
|
helper: '{{#if post.author.cover}}'
|
|
589
627
|
},
|
|
@@ -594,7 +632,7 @@ let rules = {
|
|
|
594
632
|
details: oneLineTrim`The <code>image</code> attribute was replaced with <code>profile_image</code>.<br>
|
|
595
633
|
Instead of <code>{{#if post.author.image}}</code>, you need to use
|
|
596
634
|
<code>{{#if post.primary_author.profile_image}}</code> or <code>{{#if post.authors.[#].profile_image}}</code>.<br>
|
|
597
|
-
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}
|
|
635
|
+
Find more information about the object attributes of <code>author</code> <a href="${docsBaseUrl}contexts/author/#author-object-attributes" target=_blank>here</a>.`,
|
|
598
636
|
regex: /{{\s*?#if\s*?post\.author\.image\s*?}}/g,
|
|
599
637
|
helper: '{{#if post.author.image}}'
|
|
600
638
|
},
|
|
@@ -685,8 +723,8 @@ let rules = {
|
|
|
685
723
|
level: 'error',
|
|
686
724
|
fatal: true,
|
|
687
725
|
rule: 'Replace <code>{{[#].currency_symbol}}</code> with <code>{{price currency=currency}}</code>.',
|
|
688
|
-
details: oneLineTrim`The
|
|
689
|
-
Find more information about the updated <code>{{price}}</code> helper <a href="${docsBaseUrl}
|
|
726
|
+
details: oneLineTrim`The <code>currency_symbol</code> attribute is no longer supported in favour of passing the currency to updated <code>{{price}}</code> helper.<br>
|
|
727
|
+
Find more information about the updated <code>{{price}}</code> helper <a href="${docsBaseUrl}helpers/price" target=_blank>here</a>.`,
|
|
690
728
|
helper: '{{[#].currency_symbol}}',
|
|
691
729
|
regex: /currency_symbol/g
|
|
692
730
|
}
|