gscan 4.22.0 → 4.23.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/README.md +7 -6
- package/app/tpl/index.hbs +1 -0
- package/bin/cli.js +5 -0
- package/lib/ast-linter/rules/index.js +1 -0
- package/lib/ast-linter/rules/internal/scope.js +14 -0
- package/lib/ast-linter/rules/lint-no-author-helper-in-post-page-context.js +25 -0
- package/lib/checker.js +1 -1
- package/lib/checks/010-package-json.js +70 -11
- package/lib/checks/090-template-syntax.js +1 -1
- package/lib/specs/canary.js +22 -267
- package/lib/specs/index.js +1 -1
- package/lib/specs/v4.js +306 -0
- package/lib/utils/index.js +1 -1
- package/lib/utils/versions.json +6 -2
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ In addition, an **error** can be marked as **fatal**. A **fatal error** means, l
|
|
|
18
18
|
|
|
19
19
|
In Ghost, we call GScan on boot. If any fatal errors are detected, the blog will not boot. In Ghost(Pro) and in Ghost-CLI we call GScan as part of major upgrades. The upgrade will not be allowed to continue if any fatal errors are detected.
|
|
20
20
|
|
|
21
|
-
Errors are only
|
|
21
|
+
Errors are only marked as **fatal errors** if they would cause errors, and therefore should block a boot or an upgrade.
|
|
22
22
|
|
|
23
23
|
### Tooling
|
|
24
24
|
When developing new rules or testing gscan following tools are great to have in the toolbelt:
|
|
@@ -46,12 +46,13 @@ To run a local zip file through the checks:
|
|
|
46
46
|
|
|
47
47
|
`gscan /path/to/theme.zip -z`
|
|
48
48
|
|
|
49
|
-
By default, GScan scans themes for the latest Ghost version compatibility. You can also specify a Ghost version by using the following parameters (for Ghost 1.0, 2.0, 3.0 and
|
|
49
|
+
By default, GScan scans themes for the latest Ghost version compatibility. You can also specify a Ghost version by using the following parameters (for Ghost 1.0, 2.0, 3.0, 4.0 and 5.0):
|
|
50
50
|
|
|
51
51
|
`--v1` or `-1`
|
|
52
52
|
`--v2` or `-2`
|
|
53
53
|
`--v3` or `-3`
|
|
54
|
-
`--v4` or `-4`
|
|
54
|
+
`--v4` or `-4`
|
|
55
|
+
`--v5` or `-5` or `--canary`
|
|
55
56
|
|
|
56
57
|
Use the `--canary` parameter to check for the upcoming Ghost version.
|
|
57
58
|
|
|
@@ -72,9 +73,9 @@ gscan.checkZip({
|
|
|
72
73
|
path: 'path-to-zip',
|
|
73
74
|
// if you need to check the theme for a different
|
|
74
75
|
// major Ghost version, you can pass it. Currently
|
|
75
|
-
// v1, v2, v3 and canary are supported. Default is
|
|
76
|
-
// the latest Ghost version
|
|
77
|
-
// checkVersion: '
|
|
76
|
+
// v1, v2, v3, v4 and canary (v5) are supported. Default is
|
|
77
|
+
// the latest Ghost version 4.0:
|
|
78
|
+
// checkVersion: 'v4',
|
|
78
79
|
name: 'my-theme'
|
|
79
80
|
}).then(function (result) {
|
|
80
81
|
console.log(result);
|
package/app/tpl/index.hbs
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
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
25
|
<option value="canary" selected>{{ghostVersions.canary.major}}</option>
|
|
26
|
+
<option value="v4">{{ghostVersions.v4.major}}</option>
|
|
26
27
|
<option value="v3">{{ghostVersions.v3.major}}</option>
|
|
27
28
|
<option value="v2">{{ghostVersions.v2.major}}</option>
|
|
28
29
|
<option value="v1">{{ghostVersions.v1.major}}</option>
|
package/bin/cli.js
CHANGED
|
@@ -53,6 +53,9 @@ prettyCLI
|
|
|
53
53
|
.boolean('-4, --v4', {
|
|
54
54
|
desc: 'Check theme for Ghost 4.0 compatibility'
|
|
55
55
|
})
|
|
56
|
+
.boolean('-5, --v5', {
|
|
57
|
+
desc: 'Check theme for Ghost 4.0 compatibility'
|
|
58
|
+
})
|
|
56
59
|
.boolean('-c, --canary', {
|
|
57
60
|
desc: 'Check theme for upcoming Ghost version compatibility'
|
|
58
61
|
})
|
|
@@ -75,6 +78,8 @@ prettyCLI
|
|
|
75
78
|
cliOptions.checkVersion = 'v3';
|
|
76
79
|
} else if (argv.v4) {
|
|
77
80
|
cliOptions.checkVersion = 'v4';
|
|
81
|
+
} else if (argv.v5) {
|
|
82
|
+
cliOptions.checkVersion = 'v5';
|
|
78
83
|
} else if (argv.canary) {
|
|
79
84
|
cliOptions.checkVersion = 'canary';
|
|
80
85
|
} else {
|
|
@@ -2,6 +2,7 @@ module.exports = {
|
|
|
2
2
|
'GS090-NO-IMG-URL-IN-CONDITIONALS': require('./lint-no-img-url-in-conditionals'),
|
|
3
3
|
'GS090-NO-UNKNOWN-CUSTOM-THEME-SETTINGS': require('./lint-no-unknown-custom-theme-settings'),
|
|
4
4
|
'GS090-NO-UNKNOWN-CUSTOM-THEME-SELECT-VALUE-IN-MATCH': require('./lint-no-unknown-custom-theme-select-value-in-match'),
|
|
5
|
+
'GS090-NO-AUTHOR-HELPER-IN-POST-CONTEXT': require('./lint-no-author-helper-in-post-page-context'),
|
|
5
6
|
'no-multi-param-conditionals': require('./lint-no-multi-param-conditionals'),
|
|
6
7
|
'no-nested-async-helpers': require('./lint-no-nested-async-helpers'),
|
|
7
8
|
'no-prev-next-post-outside-post-context': require('./lint-no-prev-next-post-outside-post-context'),
|
|
@@ -190,6 +190,20 @@ class Scope {
|
|
|
190
190
|
return this.currentFrame && this.currentFrame.context === context || false;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
hasParentContext(context) {
|
|
194
|
+
let found = false;
|
|
195
|
+
|
|
196
|
+
if (this.frames && this.frames.length) {
|
|
197
|
+
this.frames.forEach((frame) => {
|
|
198
|
+
if (frame.nodeName === context) {
|
|
199
|
+
found = true;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return found;
|
|
205
|
+
}
|
|
206
|
+
|
|
193
207
|
isLocal(node) {
|
|
194
208
|
// @foo MustacheStatements are referencing globals rather than locals
|
|
195
209
|
if (node.type === 'MustacheStatement' && node.path.data) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const Rule = require('./base');
|
|
2
|
+
const {getNodeName, logNode} = require('../helpers');
|
|
3
|
+
|
|
4
|
+
module.exports = class NoAuthorHelperInPostContext extends Rule {
|
|
5
|
+
_checkForHelerInPostContext(node) {
|
|
6
|
+
const nodeName = getNodeName(node);
|
|
7
|
+
const isAuthorHelper = (nodeName === 'author');
|
|
8
|
+
const isPostContext = this.scope.hasParentContext('post');
|
|
9
|
+
|
|
10
|
+
if (isAuthorHelper && isPostContext) {
|
|
11
|
+
this.log({
|
|
12
|
+
message: `${logNode(node)} should not be used in ${this.scope.currentFrame.context} 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
|
+
visitor() {
|
|
21
|
+
return {
|
|
22
|
+
MustacheStatement: this._checkForHelerInPostContext.bind(this)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
};
|
package/lib/checker.js
CHANGED
|
@@ -27,7 +27,7 @@ const check = function checkAll(themePath, options = {}) {
|
|
|
27
27
|
const passedVersion = _.get(options, 'checkVersion', versions.default);
|
|
28
28
|
let version = passedVersion;
|
|
29
29
|
|
|
30
|
-
if (passedVersion === '
|
|
30
|
+
if (passedVersion === 'v5') {
|
|
31
31
|
version = 'canary';
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -33,14 +33,15 @@ const v2PackageJSONValidationRules = _.extend({},
|
|
|
33
33
|
|
|
34
34
|
const v3PackageJSONConditionalRules = {};
|
|
35
35
|
const v3PackageJSONValidationRules = _.extend({},
|
|
36
|
-
{
|
|
36
|
+
{isNotPresentEngineGhostAPI: 'GS010-PJ-GHOST-API'},
|
|
37
37
|
{isv01EngineGhostAPI: 'GS010-PJ-GHOST-API-V01'},
|
|
38
38
|
v3PackageJSONConditionalRules
|
|
39
39
|
);
|
|
40
40
|
|
|
41
|
-
const
|
|
42
|
-
const
|
|
41
|
+
const v4PackageJSONConditionalRules = {};
|
|
42
|
+
const v4PackageJSONValidationRules = _.extend({},
|
|
43
43
|
{isv2EngineGhostAPI: 'GS010-PJ-GHOST-API-V2'},
|
|
44
|
+
{isPresentEngineGhostAPI: 'GS010-PJ-GHOST-API-PRESENT'},
|
|
44
45
|
{hasTooManyCustomThemeSettings: 'GS010-PJ-CUST-THEME-TOTAL-SETTINGS'},
|
|
45
46
|
{customThemeSettingsMustBeSnakecased: 'GS010-PJ-CUST-THEME-SETTINGS-CASE'},
|
|
46
47
|
{unkownCustomThemeSettingsType: 'GS010-PJ-CUST-THEME-SETTINGS-TYPE'},
|
|
@@ -50,9 +51,12 @@ const canaryPackageJSONValidationRules = _.extend({},
|
|
|
50
51
|
{invalidCustomThemeSetingBooleanDefault: 'GS010-PJ-CUST-THEME-SETTINGS-BOOLEAN-DEFAULT'},
|
|
51
52
|
{invalidCustomThemeSetingColorDefault: 'GS010-PJ-CUST-THEME-SETTINGS-COLOR-DEFAULT'},
|
|
52
53
|
{invalidCustomThemeSetingImageDefault: 'GS010-PJ-CUST-THEME-SETTINGS-IMAGE-DEFAULT'},
|
|
53
|
-
|
|
54
|
+
v4PackageJSONConditionalRules
|
|
54
55
|
);
|
|
55
56
|
|
|
57
|
+
const canaryPackageJSONConditionalRules = {};
|
|
58
|
+
const canaryPackageJSONValidationRules = _.extend({});
|
|
59
|
+
|
|
56
60
|
_private.validatePackageJSONFields = function validatePackageJSONFields(packageJSON, theme, packageJSONValidationRules) {
|
|
57
61
|
let failed = [];
|
|
58
62
|
const passedRulesToOmit = [];
|
|
@@ -109,6 +113,10 @@ _private.validatePackageJSONFields = function validatePackageJSONFields(packageJ
|
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
if (!packageJSON.engines || !packageJSON.engines['ghost-api']) {
|
|
116
|
+
markFailed('isNotPresentEngineGhostAPI');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (packageJSON.engines && packageJSON.engines['ghost-api']) {
|
|
112
120
|
markFailed('isPresentEngineGhostAPI');
|
|
113
121
|
}
|
|
114
122
|
|
|
@@ -221,15 +229,66 @@ module.exports = function checkPackageJSON(theme, options) {
|
|
|
221
229
|
packageJSONValidationRules = v1PackageJSONValidationRules;
|
|
222
230
|
packageJSONConditionalRules = v1PackageJSONConditionalRules;
|
|
223
231
|
} else if (checkVersion === 'v2') {
|
|
224
|
-
packageJSONValidationRules = _.merge(
|
|
225
|
-
|
|
232
|
+
packageJSONValidationRules = _.merge(
|
|
233
|
+
{},
|
|
234
|
+
v1PackageJSONValidationRules,
|
|
235
|
+
v2PackageJSONValidationRules
|
|
236
|
+
);
|
|
237
|
+
packageJSONConditionalRules = _.merge(
|
|
238
|
+
{},
|
|
239
|
+
v1PackageJSONConditionalRules,
|
|
240
|
+
v2PackageJSONConditionalRules
|
|
241
|
+
);
|
|
226
242
|
} else if (checkVersion === 'v3') {
|
|
227
|
-
packageJSONValidationRules = _.merge(
|
|
228
|
-
|
|
243
|
+
packageJSONValidationRules = _.merge(
|
|
244
|
+
{},
|
|
245
|
+
v1PackageJSONValidationRules,
|
|
246
|
+
v2PackageJSONValidationRules,
|
|
247
|
+
v3PackageJSONValidationRules
|
|
248
|
+
);
|
|
249
|
+
packageJSONConditionalRules = _.merge(
|
|
250
|
+
{},
|
|
251
|
+
v1PackageJSONConditionalRules,
|
|
252
|
+
v2PackageJSONConditionalRules,
|
|
253
|
+
v3PackageJSONConditionalRules
|
|
254
|
+
);
|
|
255
|
+
} else if (checkVersion === 'v5') {
|
|
256
|
+
packageJSONValidationRules = _.merge(
|
|
257
|
+
{},
|
|
258
|
+
v1PackageJSONValidationRules,
|
|
259
|
+
v2PackageJSONValidationRules,
|
|
260
|
+
v3PackageJSONValidationRules,
|
|
261
|
+
v4PackageJSONValidationRules,
|
|
262
|
+
canaryPackageJSONValidationRules
|
|
263
|
+
);
|
|
264
|
+
delete packageJSONValidationRules.isNotPresentEngineGhostAPI;
|
|
265
|
+
|
|
266
|
+
packageJSONConditionalRules = _.merge(
|
|
267
|
+
{},
|
|
268
|
+
v1PackageJSONConditionalRules,
|
|
269
|
+
v2PackageJSONConditionalRules,
|
|
270
|
+
v3PackageJSONConditionalRules,
|
|
271
|
+
v4PackageJSONConditionalRules,
|
|
272
|
+
canaryPackageJSONConditionalRules
|
|
273
|
+
);
|
|
229
274
|
} else {
|
|
230
|
-
// default check for current version 'v4'
|
|
231
|
-
packageJSONValidationRules = _.merge(
|
|
232
|
-
|
|
275
|
+
// default check for current version 'v4' rules
|
|
276
|
+
packageJSONValidationRules = _.merge(
|
|
277
|
+
{},
|
|
278
|
+
v1PackageJSONValidationRules,
|
|
279
|
+
v2PackageJSONValidationRules,
|
|
280
|
+
v3PackageJSONValidationRules,
|
|
281
|
+
v4PackageJSONValidationRules
|
|
282
|
+
);
|
|
283
|
+
delete packageJSONValidationRules.isNotPresentEngineGhostAPI;
|
|
284
|
+
|
|
285
|
+
packageJSONConditionalRules = _.merge(
|
|
286
|
+
{},
|
|
287
|
+
v1PackageJSONConditionalRules,
|
|
288
|
+
v2PackageJSONConditionalRules,
|
|
289
|
+
v3PackageJSONConditionalRules,
|
|
290
|
+
v4PackageJSONConditionalRules
|
|
291
|
+
);
|
|
233
292
|
}
|
|
234
293
|
|
|
235
294
|
let [packageJSON] = _.filter(theme.files, {file: packageJSONFileName});
|
|
@@ -49,7 +49,6 @@ function getCustomThemeSettings(theme) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const checkTemplatesCompile = function checkTemplatesCompile(theme, options) {
|
|
52
|
-
const failures = [];
|
|
53
52
|
const checkVersion = _.get(options, 'checkVersion', versions.default);
|
|
54
53
|
const ruleSet = spec.get([checkVersion]);
|
|
55
54
|
const customThemeSettings = getCustomThemeSettings(theme);
|
|
@@ -63,6 +62,7 @@ const checkTemplatesCompile = function checkTemplatesCompile(theme, options) {
|
|
|
63
62
|
});
|
|
64
63
|
|
|
65
64
|
_.each(rulesToCheck, function (check, ruleCode) {
|
|
65
|
+
const failures = [];
|
|
66
66
|
const processFile = processFileFunction(
|
|
67
67
|
theme.files,
|
|
68
68
|
failures,
|
package/lib/specs/canary.js
CHANGED
|
@@ -1,291 +1,46 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
2
|
const oneLineTrim = require('common-tags/lib/oneLineTrim');
|
|
3
|
-
const previousSpec = require('./
|
|
3
|
+
const previousSpec = require('./v4');
|
|
4
4
|
const ghostVersions = require('../utils').versions;
|
|
5
5
|
const docsBaseUrl = `https://ghost.org/docs/api/handlebars-themes/`;
|
|
6
|
-
const prevDocsBaseUrl = `https://themes.ghost.org/v${ghostVersions.
|
|
6
|
+
const prevDocsBaseUrl = `https://themes.ghost.org/v${ghostVersions.canary.docs}/docs/`;
|
|
7
7
|
const prevDocsBaseUrlRegEx = new RegExp(prevDocsBaseUrl, 'g');
|
|
8
8
|
|
|
9
9
|
const previousKnownHelpers = previousSpec.knownHelpers;
|
|
10
10
|
const previousTemplates = previousSpec.templates;
|
|
11
11
|
const previousRules = previousSpec.rules;
|
|
12
12
|
|
|
13
|
-
function cssCardRule(cardName, className) {
|
|
14
|
-
return {
|
|
15
|
-
level: 'warning',
|
|
16
|
-
rule: `The <code>.${className}</code> CSS class is required to appear styled in your theme`,
|
|
17
|
-
details: oneLineTrim`The <code>.${className}</code> CSS class is required otherwise the ${cardName} card will appear unstyled.
|
|
18
|
-
Find out more about required theme changes for the Koenig editor <a href="${docsBaseUrl}editor/" target=_blank>here</a>.`,
|
|
19
|
-
regex: new RegExp(`\\.${className}`, 'g'),
|
|
20
|
-
className: `.${className}`,
|
|
21
|
-
css: true,
|
|
22
|
-
cardAsset: cardName
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
13
|
// assign new or overwrite existing knownHelpers, templates, or rules here:
|
|
27
|
-
let knownHelpers = [
|
|
14
|
+
let knownHelpers = [];
|
|
28
15
|
let templates = [];
|
|
29
16
|
let rules = {
|
|
30
17
|
// New rules
|
|
31
|
-
'GS010-PJ-GHOST-API': {
|
|
32
|
-
level: 'warning',
|
|
33
|
-
rule: '<code>package.json</code> property <code>"engines.ghost-api"</code> is recommended. Otherwise, it falls back to "v4"',
|
|
34
|
-
details: oneLineTrim`Add <code>"ghost-api"</code> to your <code>package.json</code>. E.g. <code>{"engines": {"ghost-api": "v4"}}</code>.<br>
|
|
35
|
-
If no <code>"ghost-api"</code> property is provided, Ghost will use its default setting of "v4" Ghost API.<br>
|
|
36
|
-
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
37
|
-
},
|
|
38
|
-
'GS010-PJ-GHOST-API-V01': {
|
|
39
|
-
level: 'error',
|
|
40
|
-
rule: '<code>package.json</code> property <code>"engines.ghost-api"</code> is incompatible with current version of Ghost API and will fall back to "v4"',
|
|
41
|
-
details: oneLineTrim`Change <code>"ghost-api"</code> in your <code>package.json</code> to higher version. E.g. <code>{"engines": {"ghost-api": "v4"}}</code>.<br>
|
|
42
|
-
If <code>"ghost-api"</code> property is left at "v0.1", Ghost will use its default setting of "v4".<br>
|
|
43
|
-
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
44
|
-
},
|
|
45
|
-
'GS010-PJ-GHOST-API-V2': {
|
|
46
|
-
level: 'warning',
|
|
47
|
-
rule: '<code>package.json</code> property <code>"engines.ghost-api"</code> is using a deprecated version of Ghost API',
|
|
48
|
-
details: oneLineTrim`Change <code>"ghost-api"</code> in your <code>package.json</code> to higher version. E.g. <code>{"engines": {"ghost-api": "v4"}}</code>.<br>
|
|
49
|
-
If <code>"ghost-api"</code> property is left at "v2", it will stop working with next major version upgrade and default to v5.<br>
|
|
50
|
-
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
51
|
-
},
|
|
52
|
-
'GS010-PJ-CUST-THEME-TOTAL-SETTINGS': {
|
|
53
|
-
level: 'error',
|
|
54
|
-
rule: '<code>package.json</code> property <code>"config.custom"</code> contains too many settings',
|
|
55
|
-
details: oneLineTrim`Remove key from <code>"config.custom"</code> in your <code>package.json</code> to have less than or exactly 15 settings.<br>
|
|
56
|
-
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
57
|
-
},
|
|
58
|
-
'GS010-PJ-CUST-THEME-SETTINGS-CASE': {
|
|
59
|
-
level: 'error',
|
|
60
|
-
rule: '<code>package.json</code> property <code>"config.custom"</code> contains a property that isn\'t snake-cased',
|
|
61
|
-
details: oneLineTrim`Rewrite all property in <code>"config.custom"</code> in your <code>package.json</code> in snake case.<br>
|
|
62
|
-
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
63
|
-
},
|
|
64
|
-
'GS010-PJ-CUST-THEME-SETTINGS-TYPE': {
|
|
65
|
-
level: 'error',
|
|
66
|
-
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> should have a known <code>"type"</code>.',
|
|
67
|
-
details: oneLineTrim`Only use the following types: <code>"select"</code>, <code>"boolean"</code>, <code>"color"</code>, <code>"image"</code>, <code>"text"</code>.<br>
|
|
68
|
-
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
69
|
-
},
|
|
70
|
-
'GS010-PJ-CUST-THEME-SETTINGS-GROUP': {
|
|
71
|
-
level: 'recommendation',
|
|
72
|
-
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> should have a known <code>"group"</code>.',
|
|
73
|
-
details: oneLineTrim`Only use the following groups: <code>"post"</code>, <code>"homepage"</code>.<br>
|
|
74
|
-
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
75
|
-
},
|
|
76
|
-
'GS010-PJ-CUST-THEME-SETTINGS-SELECT-OPTIONS': {
|
|
77
|
-
level: 'error',
|
|
78
|
-
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> of type <code>"select"</code> need to have at least 2 <code>"options"</code>.',
|
|
79
|
-
details: oneLineTrim`Make sure there is at least 2 <code>"options"</code> in each <code>"select"</code> custom theme property.<br>
|
|
80
|
-
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
81
|
-
},
|
|
82
|
-
'GS010-PJ-CUST-THEME-SETTINGS-SELECT-DEFAULT': {
|
|
83
|
-
level: 'error',
|
|
84
|
-
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> of type <code>"select"</code> need to have a valid <code>"default"</code>.',
|
|
85
|
-
details: oneLineTrim`Make sure the <code>"default"</code> property matches a value in <code>"options"</code> of the same <code>"select"</code>.<br>
|
|
86
|
-
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
87
|
-
},
|
|
88
|
-
'GS010-PJ-CUST-THEME-SETTINGS-BOOLEAN-DEFAULT': {
|
|
89
|
-
level: 'error',
|
|
90
|
-
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> of type <code>"boolean"</code> need to have a valid <code>"default"</code>.',
|
|
91
|
-
details: oneLineTrim`Make sure the <code>"default"</code> property is either <code>true</code> or <code>false</code>.<br>
|
|
92
|
-
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
93
|
-
},
|
|
94
|
-
'GS010-PJ-CUST-THEME-SETTINGS-COLOR-DEFAULT': {
|
|
18
|
+
'GS010-PJ-GHOST-API-PRESENT': {
|
|
95
19
|
level: 'error',
|
|
96
|
-
rule: '<code>package.json</code>
|
|
97
|
-
details: oneLineTrim`
|
|
20
|
+
rule: '<code>package.json</code> property <code>"engines.ghost-api"</code> is not supported.',
|
|
21
|
+
details: oneLineTrim`Remove <code>"ghost-api"</code> from your <code>package.json</code>.<br>
|
|
22
|
+
The <code>ghost-api</code> is not supported starting Ghost v5 and should not be used.
|
|
98
23
|
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
99
24
|
},
|
|
100
|
-
'
|
|
25
|
+
'GS001-DEPR-BLOG': {
|
|
101
26
|
level: 'error',
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
'GS001-DEPR-LABS-MEMBERS': {
|
|
107
|
-
level: 'warning',
|
|
108
|
-
rule: 'The <code>{{@labs.members}}</code> helper should not be used.',
|
|
109
|
-
details: oneLineTrim`Remove <code>{{@labs.members}}</code> from the theme.<br>
|
|
110
|
-
The <code>{{@labs.members}}</code> helper will always return <code>true</code> in Ghost v4 and will be removed from Ghost v5, at which point it will return <code>null</code> and evaluate to <code>false</code>.
|
|
111
|
-
Find more information about the <code>@labs</code> property <a href="${docsBaseUrl}helpers/labs/" target=_blank>here</a>.`,
|
|
112
|
-
regex: /@labs\.members/g,
|
|
113
|
-
helper: '{{@labs.members}}'
|
|
114
|
-
},
|
|
115
|
-
'GS080-FEACH-POSTS': {
|
|
116
|
-
level: 'warning',
|
|
117
|
-
rule: 'The default visibility for posts in <code>{{#foreach}}</code> block helper has changed in v4.',
|
|
118
|
-
details: oneLineTrim`The default visibility for posts in <code>{{#foreach}}</code> block helper has changed from <code>public</code> to <code>all</code> in Ghost v4.
|
|
119
|
-
Find more information about the <code>{{foreach}}</code> helper <a href="${docsBaseUrl}helpers/foreach/" target=_blank>here</a>.`,
|
|
120
|
-
regex: /{{\s*?#foreach\s*?\w*?\s*?}}/g,
|
|
121
|
-
helper: '{{#foreach}}',
|
|
122
|
-
validInAPI: ['v3']
|
|
123
|
-
},
|
|
124
|
-
'GS080-CARD-LAST4': {
|
|
125
|
-
level: 'warning',
|
|
126
|
-
rule: 'The <code>default_payment_card_last4</code> field now coalesces to <code>****</code> in Ghost 4.x instead of null.',
|
|
127
|
-
details: oneLineTrim`The <code>default_payment_card_last4</code> field no longer outputs a falsy(null) value in case of missing card details starting from Ghost 4.x and instead coalesces to <code>****</code>
|
|
128
|
-
Find more information about the <code>default_payment_card_last4</code> attribute <a href="${docsBaseUrl}members/#subscription-attributes" target=_blank>here</a>.`,
|
|
129
|
-
regex: /default_payment_card_last4/g,
|
|
130
|
-
helper: '{{default_payment_card_last4}}',
|
|
131
|
-
validInAPI: ['v3']
|
|
132
|
-
},
|
|
133
|
-
'GS080-FEACH-PV': {
|
|
134
|
-
level: 'recommendation',
|
|
135
|
-
rule: 'The use of <code>visibility="all"</code> is no longer required for posts in <code>{{#foreach}}</code> helper.',
|
|
136
|
-
details: oneLineTrim`The default visibility in <code>{{#foreach}}</code> helper for posts has changed in v4 from "public" to "all" and is no longer required when looping over posts.
|
|
137
|
-
Check out the documentation for <code>{{#foreach}}</code> <a href="${docsBaseUrl}helpers/foreach/" target=_blank>here</a>.`,
|
|
138
|
-
regex: /{{\s*?#foreach\b[\w\s='"]*?visibility=("|')all("|')[\w\s='"]*?}}/g,
|
|
139
|
-
helper: '{{#foreach}}',
|
|
140
|
-
validInAPI: ['v3']
|
|
141
|
-
},
|
|
142
|
-
'GS001-DEPR-CURR-SYM': {
|
|
143
|
-
level: 'warning',
|
|
144
|
-
rule: 'Replace <code>{{[#].currency_symbol}}</code> with <code>{{price currency=currency}}</code>.',
|
|
145
|
-
details: oneLineTrim`The hardcoded <code>currency_symbol</code> attribute was removed in favour of passing the currency to updated <code>{{price}}</code> helper.
|
|
146
|
-
Find more information about the updated <code>{{price}}</code> helper <a href="${docsBaseUrl}members/#the-price-helper" target=_blank>here</a>.`,
|
|
147
|
-
helper: '{{[#].currency_symbol}}',
|
|
148
|
-
regex: /currency_symbol/g
|
|
149
|
-
},
|
|
150
|
-
'GS001-DEPR-SITE-LANG': {
|
|
151
|
-
level: 'warning',
|
|
152
|
-
rule: 'The <code>{{@site.lang}}</code> helper should be replaced with <code>{{@site.locale}}</code>',
|
|
153
|
-
details: oneLineTrim`Replace <code>{{@site.lang}}</code> helper with <code>{{@site.locale}}</code>.<br>
|
|
154
|
-
The <code>{{@site.lang}}</code> helper will be removed in next version of Ghost and should not be used.
|
|
27
|
+
fatal: true,
|
|
28
|
+
rule: 'The <code>{{@blog}}</code> helper should be replaced with <code>{{@site}}</code>',
|
|
29
|
+
details: oneLineTrim`With the introduction of the Content API <code>{{@blog}}</code> became deprecated in favour of <code>{{@site}}</code>.<br>
|
|
30
|
+
The <code>{{@blog}}</code> helper was removed in Ghost v5 and should not be used.
|
|
155
31
|
Find more information about the <code>@site</code> property <a href="${docsBaseUrl}helpers/site/" target=_blank>here</a>.`,
|
|
156
|
-
regex:
|
|
157
|
-
helper: '{{@
|
|
158
|
-
},
|
|
159
|
-
'GS070-VALID-TRANSLATIONS': {
|
|
160
|
-
level: 'error',
|
|
161
|
-
rule: 'Theme translations must be parsable',
|
|
162
|
-
fatal: true, // overwritten from v3 to be fatal
|
|
163
|
-
details: oneLineTrim`Theme translations (located in <code>locales/*.json</code>) need to be readable by the node JSON parser, or they will not be applied.`
|
|
164
|
-
},
|
|
165
|
-
'GS090-NO-IMG-URL-IN-CONDITIONALS': {
|
|
166
|
-
level: 'warning',
|
|
167
|
-
rule: 'The {{img_url}} helper should not be used as a parameter to {{#if}} or {{#unless}}',
|
|
168
|
-
fatal: false,
|
|
169
|
-
details: oneLineTrim`The {{img_url}} helper should not be used as a parameter to {{#if}} or {{#unless}}`
|
|
32
|
+
regex: /{{\s*?@blog\.[a-zA-Z0-9_]+\s*?}}/g,
|
|
33
|
+
helper: '{{@blog}}'
|
|
170
34
|
},
|
|
171
|
-
'GS090-NO-
|
|
35
|
+
'GS090-NO-AUTHOR-HELPER-IN-POST-CONTEXT': {
|
|
172
36
|
level: 'error',
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
details: oneLineTrim`The
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
fatal: false,
|
|
181
|
-
details: oneLineTrim`Custom theme settings of type <code>select</code> can only be compared to their defined <code>options</code> when used in a <code>match</code> block.`
|
|
182
|
-
},
|
|
183
|
-
'GS100-NO-UNUSED-CUSTOM-THEME-SETTING': {
|
|
184
|
-
level: 'error',
|
|
185
|
-
rule: 'A custom theme setting defined in <code>package.json</code> hasn\'t been used in any theme file.',
|
|
186
|
-
details: oneLineTrim`Custom theme settings defined in <code>package.json</code> must be used at least once in the theme templates.`
|
|
187
|
-
},
|
|
188
|
-
|
|
189
|
-
'GS050-CSS-KGCO': cssCardRule('callout', 'kg-callout-card'),
|
|
190
|
-
'GS050-CSS-KGCOE': cssCardRule('callout', 'kg-callout-card-emoji'),
|
|
191
|
-
'GS050-CSS-KGCOT': cssCardRule('callout', 'kg-callout-card-text'),
|
|
192
|
-
'GS050-CSS-KGCOBGGY': cssCardRule('callout', 'kg-callout-card-background-grey'),
|
|
193
|
-
'GS050-CSS-KGCOBGW': cssCardRule('callout', 'kg-callout-card-background-white'),
|
|
194
|
-
'GS050-CSS-KGCOBGB': cssCardRule('callout', 'kg-callout-card-background-blue'),
|
|
195
|
-
'GS050-CSS-KGCOBGGN': cssCardRule('callout', 'kg-callout-card-background-green'),
|
|
196
|
-
'GS050-CSS-KGCOBGY': cssCardRule('callout', 'kg-callout-card-background-yellow'),
|
|
197
|
-
'GS050-CSS-KGCOBGR': cssCardRule('callout', 'kg-callout-card-background-red'),
|
|
198
|
-
'GS050-CSS-KGCOBGPK': cssCardRule('callout', 'kg-callout-card-background-pink'),
|
|
199
|
-
'GS050-CSS-KGCOBGPE': cssCardRule('callout', 'kg-callout-card-background-purple'),
|
|
200
|
-
'GS050-CSS-KGCOBGA': cssCardRule('callout', 'kg-callout-card-background-accent'),
|
|
201
|
-
|
|
202
|
-
'GS050-CSS-KG-NFT': cssCardRule('nft', 'kg-nft-card'),
|
|
203
|
-
'GS050-CSS-KG-NFTCO': cssCardRule('nft', 'kg-nft-card-container'),
|
|
204
|
-
'GS050-CSS-KG-NFTMD': cssCardRule('nft', 'kg-nft-metadata'),
|
|
205
|
-
'GS050-CSS-KG-NFTIMG': cssCardRule('nft', 'kg-nft-image'),
|
|
206
|
-
'GS050-CSS-KG-NFTHD': cssCardRule('nft', 'kg-nft-header'),
|
|
207
|
-
'GS050-CSS-KG-NFTTIT': cssCardRule('nft', 'kg-nft-title'),
|
|
208
|
-
'GS050-CSS-KG-NFTLG': cssCardRule('nft', 'kg-nft-logo'),
|
|
209
|
-
'GS050-CSS-KG-NFTCTR': cssCardRule('nft', 'kg-nft-creator'),
|
|
210
|
-
'GS050-CSS-KG-NFTDSC': cssCardRule('nft', 'kg-nft-description'),
|
|
211
|
-
|
|
212
|
-
'GS050-CSS-KGTGL': cssCardRule('toggle', 'kg-toggle-card'),
|
|
213
|
-
'GS050-CSS-KGTGLH': cssCardRule('toggle', 'kg-toggle-heading'),
|
|
214
|
-
'GS050-CSS-KGTGLHT': cssCardRule('toggle', 'kg-toggle-heading-text'),
|
|
215
|
-
'GS050-CSS-KGTGLIC': cssCardRule('toggle', 'kg-toggle-card-icon'),
|
|
216
|
-
'GS050-CSS-KGTGLC': cssCardRule('toggle', 'kg-toggle-content'),
|
|
217
|
-
|
|
218
|
-
'GS050-CSS-KGAUD': cssCardRule('audio', 'kg-audio-card'),
|
|
219
|
-
'GS050-CSS-KGAUDTHUMB': cssCardRule('audio', 'kg-audio-thumbnail'),
|
|
220
|
-
'GS050-CSS-KGAUDTHUMBPL': cssCardRule('audio', 'kg-audio-thumbnail.placeholder'),
|
|
221
|
-
'GS050-CSS-KGAUDPLCNT': cssCardRule('audio', 'kg-audio-player-container'),
|
|
222
|
-
'GS050-CSS-KGAUDTI': cssCardRule('audio', 'kg-audio-title'),
|
|
223
|
-
'GS050-CSS-KGAUDPL': cssCardRule('audio', 'kg-audio-player'),
|
|
224
|
-
'GS050-CSS-KGAUDCURRTM': cssCardRule('audio', 'kg-audio-current-time'),
|
|
225
|
-
'GS050-CSS-KGAUDTM': cssCardRule('audio', 'kg-audio-time'),
|
|
226
|
-
'GS050-CSS-KGAUDDUR': cssCardRule('audio', 'kg-audio-duration'),
|
|
227
|
-
'GS050-CSS-KGAUDPLICO': cssCardRule('audio', 'kg-audio-play-icon'),
|
|
228
|
-
'GS050-CSS-KGAUDPAUICO': cssCardRule('audio', 'kg-audio-pause-icon'),
|
|
229
|
-
'GS050-CSS-KGAUDSKSL': cssCardRule('audio', 'kg-audio-seek-slider'),
|
|
230
|
-
'GS050-CSS-KGAUDPLRT': cssCardRule('audio', 'kg-audio-playback-rate'),
|
|
231
|
-
'GS050-CSS-KGAUDMTICO': cssCardRule('audio', 'kg-audio-mute-icon'),
|
|
232
|
-
'GS050-CSS-KGAUDUNMTICO': cssCardRule('audio', 'kg-audio-unmute-icon'),
|
|
233
|
-
'GS050-CSS-KGAUDVOLSL': cssCardRule('audio', 'kg-audio-volume-slider'),
|
|
234
|
-
|
|
235
|
-
'GS050-CSS-KGVID': cssCardRule('video', 'kg-video-card'),
|
|
236
|
-
'GS050-CSS-KGVIDHD': cssCardRule('video', 'kg-video-hide'),
|
|
237
|
-
'GS050-CSS-KGVIDCNT': cssCardRule('video', 'kg-video-container'),
|
|
238
|
-
'GS050-CSS-KGVIDOVL': cssCardRule('video', 'kg-video-overlay'),
|
|
239
|
-
'GS050-CSS-KGVIDLGPLICO': cssCardRule('video', 'kg-video-large-play-icon'),
|
|
240
|
-
'GS050-CSS-KGVIDTHUMB': cssCardRule('video', 'kg-video-thumbnail'),
|
|
241
|
-
'GS050-CSS-KGVIDTHUMBPL': cssCardRule('video', 'kg-video-thumbnail.placeholder'),
|
|
242
|
-
'GS050-CSS-KGVIDPLCNT': cssCardRule('video', 'kg-video-player-container'),
|
|
243
|
-
'GS050-CSS-KGVIDTI': cssCardRule('video', 'kg-video-title'),
|
|
244
|
-
'GS050-CSS-KGVIDPL': cssCardRule('video', 'kg-video-player'),
|
|
245
|
-
'GS050-CSS-KGVIDCURRTM': cssCardRule('video', 'kg-video-current-time'),
|
|
246
|
-
'GS050-CSS-KGVIDTM': cssCardRule('video', 'kg-video-time'),
|
|
247
|
-
'GS050-CSS-KGVIDDUR': cssCardRule('video', 'kg-video-duration'),
|
|
248
|
-
'GS050-CSS-KGVIDPLICO': cssCardRule('video', 'kg-video-play-icon'),
|
|
249
|
-
'GS050-CSS-KGVIDPAUICO': cssCardRule('video', 'kg-video-pause-icon'),
|
|
250
|
-
'GS050-CSS-KGVIDSKSL': cssCardRule('video', 'kg-video-seek-slider'),
|
|
251
|
-
'GS050-CSS-KGVIDPLRT': cssCardRule('video', 'kg-video-playback-rate'),
|
|
252
|
-
'GS050-CSS-KGVIDMTICO': cssCardRule('video', 'kg-video-mute-icon'),
|
|
253
|
-
'GS050-CSS-KGVIDUNMTICO': cssCardRule('video', 'kg-video-unmute-icon'),
|
|
254
|
-
'GS050-CSS-KGVIDVOLSL': cssCardRule('video', 'kg-video-volume-slider'),
|
|
255
|
-
|
|
256
|
-
'GS050-CSS-KGBTN': cssCardRule('button', 'kg-button-card'),
|
|
257
|
-
'GS050-CSS-KGBTNL': cssCardRule('button', 'kg-button-card.kg-align-left'),
|
|
258
|
-
'GS050-CSS-KGBTNC': cssCardRule('button', 'kg-button-card.kg-align-center'),
|
|
259
|
-
'GS050-CSS-KGBTNBTN': cssCardRule('button', 'kg-btn'),
|
|
260
|
-
'GS050-CSS-KGBTNBTNA': cssCardRule('button', 'kg-btn-accent'),
|
|
261
|
-
|
|
262
|
-
'GS050-CSS-KGPR': cssCardRule('product', 'kg-product-card'),
|
|
263
|
-
'GS050-CSS-KGPRBTNA': cssCardRule('product', 'kg-product-card-btn-accent'),
|
|
264
|
-
'GS050-CSS-KGPRBTN': cssCardRule('product', 'kg-product-card-button'),
|
|
265
|
-
'GS050-CSS-KGPRCO': cssCardRule('product', 'kg-product-card-container'),
|
|
266
|
-
'GS050-CSS-KGPRDE': cssCardRule('product', 'kg-product-card-description'),
|
|
267
|
-
'GS050-CSS-KGPRIM': cssCardRule('product', 'kg-product-card-image'),
|
|
268
|
-
'GS050-CSS-KGPRRA': cssCardRule('product', 'kg-product-card-rating'),
|
|
269
|
-
'GS050-CSS-KGPRRAA': cssCardRule('product', 'kg-product-card-rating-active'),
|
|
270
|
-
'GS050-CSS-KGPRRAS': cssCardRule('product', 'kg-product-card-rating-star'),
|
|
271
|
-
'GS050-CSS-KGPRTI': cssCardRule('product', 'kg-product-card-title'),
|
|
272
|
-
'GS050-CSS-KGPRTICO': cssCardRule('product', 'kg-product-card-title-container'),
|
|
273
|
-
|
|
274
|
-
'GS050-CSS-KGBA': cssCardRule('before-after', 'kg-before-after-card'),
|
|
275
|
-
'GS050-CSS-KGBAIA': cssCardRule('before-after', 'kg-before-after-card-image-before'),
|
|
276
|
-
'GS050-CSS-KGBAIB': cssCardRule('before-after', 'kg-before-after-card-image-after'),
|
|
277
|
-
|
|
278
|
-
'GS050-CSS-KGFL': cssCardRule('file', 'kg-file-card'),
|
|
279
|
-
'GS050-CSS-KGFLCON': cssCardRule('file', 'kg-file-card-container'),
|
|
280
|
-
'GS050-CSS-KGFLCNT': cssCardRule('file', 'kg-file-card-contents'),
|
|
281
|
-
'GS050-CSS-KGFLTTL': cssCardRule('file', 'kg-file-card-title'),
|
|
282
|
-
'GS050-CSS-KGFLCAP': cssCardRule('file', 'kg-file-card-caption'),
|
|
283
|
-
'GS050-CSS-KGFLNM': cssCardRule('file', 'kg-file-card-filename'),
|
|
284
|
-
'GS050-CSS-KGFLSZ': cssCardRule('file', 'kg-file-card-filesize'),
|
|
285
|
-
'GS050-CSS-KGFLMD': cssCardRule('file', 'kg-file-card-medium'),
|
|
286
|
-
'GS050-CSS-KGFLSM': cssCardRule('file', 'kg-file-card-small'),
|
|
287
|
-
|
|
288
|
-
'GS050-CSS-KGBQALT': cssCardRule('blockquote', 'kg-blockquote-alt')
|
|
37
|
+
fatal: true,
|
|
38
|
+
rule: 'The <code>{{author}}</code> helper should be replaces with <code>{{authors}}</code>',
|
|
39
|
+
details: oneLineTrim`The <code>{{author}}</code> helper has been deprecated since Ghost 1.22.0 in favor of <code>{{<authors>}}</code><br>
|
|
40
|
+
The <code>{{author}}</code> helper was removed in Ghost v5 and should not be used.
|
|
41
|
+
Find more information about the <code>@site</code> property <a href="${docsBaseUrl}helpers/site/" target=_blank>here</a>.`,
|
|
42
|
+
helper: '{{author}}'
|
|
43
|
+
}
|
|
289
44
|
};
|
|
290
45
|
|
|
291
46
|
knownHelpers = _.union(previousKnownHelpers, knownHelpers);
|
package/lib/specs/index.js
CHANGED
package/lib/specs/v4.js
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const oneLineTrim = require('common-tags/lib/oneLineTrim');
|
|
3
|
+
const previousSpec = require('./v3');
|
|
4
|
+
const ghostVersions = require('../utils').versions;
|
|
5
|
+
const docsBaseUrl = `https://ghost.org/docs/api/handlebars-themes/`;
|
|
6
|
+
const prevDocsBaseUrl = `https://themes.ghost.org/v${ghostVersions.v3.docs}/docs/`;
|
|
7
|
+
const prevDocsBaseUrlRegEx = new RegExp(prevDocsBaseUrl, 'g');
|
|
8
|
+
|
|
9
|
+
const previousKnownHelpers = previousSpec.knownHelpers;
|
|
10
|
+
const previousTemplates = previousSpec.templates;
|
|
11
|
+
const previousRules = previousSpec.rules;
|
|
12
|
+
|
|
13
|
+
function cssCardRule(cardName, className) {
|
|
14
|
+
return {
|
|
15
|
+
level: 'warning',
|
|
16
|
+
rule: `The <code>.${className}</code> CSS class is required to appear styled in your theme`,
|
|
17
|
+
details: oneLineTrim`The <code>.${className}</code> CSS class is required otherwise the ${cardName} card will appear unstyled.
|
|
18
|
+
Find out more about required theme changes for the Koenig editor <a href="${docsBaseUrl}editor/" target=_blank>here</a>.`,
|
|
19
|
+
regex: new RegExp(`\\.${className}`, 'g'),
|
|
20
|
+
className: `.${className}`,
|
|
21
|
+
css: true,
|
|
22
|
+
cardAsset: cardName
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// assign new or overwrite existing knownHelpers, templates, or rules here:
|
|
27
|
+
let knownHelpers = ['match'];
|
|
28
|
+
let templates = [];
|
|
29
|
+
let rules = {
|
|
30
|
+
// New rules
|
|
31
|
+
'GS010-PJ-GHOST-API-PRESENT': {
|
|
32
|
+
level: 'warning',
|
|
33
|
+
rule: '<code>package.json</code> property <code>"engines.ghost-api"</code> is deprecated.',
|
|
34
|
+
details: oneLineTrim`Remove <code>"ghost-api"</code> from your <code>package.json</code>.<br>
|
|
35
|
+
The <code>ghost-api</code> support will be removed in next major version of Ghost and should not be used.
|
|
36
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
37
|
+
},
|
|
38
|
+
'GS010-PJ-GHOST-API-V01': {
|
|
39
|
+
level: 'error',
|
|
40
|
+
rule: '<code>package.json</code> property <code>"engines.ghost-api"</code> is incompatible with current version of Ghost API and will fall back to "v4"',
|
|
41
|
+
details: oneLineTrim`Change <code>"ghost-api"</code> in your <code>package.json</code> to higher version. E.g. <code>{"engines": {"ghost-api": "v4"}}</code>.<br>
|
|
42
|
+
If <code>"ghost-api"</code> property is left at "v0.1", Ghost will use its default setting of "v4".<br>
|
|
43
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
44
|
+
},
|
|
45
|
+
'GS010-PJ-GHOST-API-V2': {
|
|
46
|
+
level: 'warning',
|
|
47
|
+
rule: '<code>package.json</code> property <code>"engines.ghost-api"</code> is using a deprecated version of Ghost API',
|
|
48
|
+
details: oneLineTrim`Change <code>"ghost-api"</code> in your <code>package.json</code> to higher version. E.g. <code>{"engines": {"ghost-api": "v4"}}</code>.<br>
|
|
49
|
+
If <code>"ghost-api"</code> property is left at "v2", it will stop working with next major version upgrade and default to v5.<br>
|
|
50
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
51
|
+
},
|
|
52
|
+
'GS010-PJ-CUST-THEME-TOTAL-SETTINGS': {
|
|
53
|
+
level: 'error',
|
|
54
|
+
rule: '<code>package.json</code> property <code>"config.custom"</code> contains too many settings',
|
|
55
|
+
details: oneLineTrim`Remove key from <code>"config.custom"</code> in your <code>package.json</code> to have less than or exactly 15 settings.<br>
|
|
56
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
57
|
+
},
|
|
58
|
+
'GS010-PJ-CUST-THEME-SETTINGS-CASE': {
|
|
59
|
+
level: 'error',
|
|
60
|
+
rule: '<code>package.json</code> property <code>"config.custom"</code> contains a property that isn\'t snake-cased',
|
|
61
|
+
details: oneLineTrim`Rewrite all property in <code>"config.custom"</code> in your <code>package.json</code> in snake case.<br>
|
|
62
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
63
|
+
},
|
|
64
|
+
'GS010-PJ-CUST-THEME-SETTINGS-TYPE': {
|
|
65
|
+
level: 'error',
|
|
66
|
+
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> should have a known <code>"type"</code>.',
|
|
67
|
+
details: oneLineTrim`Only use the following types: <code>"select"</code>, <code>"boolean"</code>, <code>"color"</code>, <code>"image"</code>, <code>"text"</code>.<br>
|
|
68
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
69
|
+
},
|
|
70
|
+
'GS010-PJ-CUST-THEME-SETTINGS-GROUP': {
|
|
71
|
+
level: 'recommendation',
|
|
72
|
+
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> should have a known <code>"group"</code>.',
|
|
73
|
+
details: oneLineTrim`Only use the following groups: <code>"post"</code>, <code>"homepage"</code>.<br>
|
|
74
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
75
|
+
},
|
|
76
|
+
'GS010-PJ-CUST-THEME-SETTINGS-SELECT-OPTIONS': {
|
|
77
|
+
level: 'error',
|
|
78
|
+
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> of type <code>"select"</code> need to have at least 2 <code>"options"</code>.',
|
|
79
|
+
details: oneLineTrim`Make sure there is at least 2 <code>"options"</code> in each <code>"select"</code> custom theme property.<br>
|
|
80
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
81
|
+
},
|
|
82
|
+
'GS010-PJ-CUST-THEME-SETTINGS-SELECT-DEFAULT': {
|
|
83
|
+
level: 'error',
|
|
84
|
+
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> of type <code>"select"</code> need to have a valid <code>"default"</code>.',
|
|
85
|
+
details: oneLineTrim`Make sure the <code>"default"</code> property matches a value in <code>"options"</code> of the same <code>"select"</code>.<br>
|
|
86
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
87
|
+
},
|
|
88
|
+
'GS010-PJ-CUST-THEME-SETTINGS-BOOLEAN-DEFAULT': {
|
|
89
|
+
level: 'error',
|
|
90
|
+
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> of type <code>"boolean"</code> need to have a valid <code>"default"</code>.',
|
|
91
|
+
details: oneLineTrim`Make sure the <code>"default"</code> property is either <code>true</code> or <code>false</code>.<br>
|
|
92
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
93
|
+
},
|
|
94
|
+
'GS010-PJ-CUST-THEME-SETTINGS-COLOR-DEFAULT': {
|
|
95
|
+
level: 'error',
|
|
96
|
+
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> of type <code>"color"</code> need to have a valid <code>"default"</code>.',
|
|
97
|
+
details: oneLineTrim`Make sure the <code>"default"</code> property is a valid 6-hexadecimal-digit color code like <code>#15171a</code>.<br>
|
|
98
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
99
|
+
},
|
|
100
|
+
'GS010-PJ-CUST-THEME-SETTINGS-IMAGE-DEFAULT': {
|
|
101
|
+
level: 'error',
|
|
102
|
+
rule: '<code>package.json</code> objects defined in <code>"config.custom"</code> of type <code>"image"</code> can\'t have a <code>"default"</code> value.',
|
|
103
|
+
details: oneLineTrim`Make sure the <code>"default"</code> property is either <code>null</code>, an empty string <code>''</code> or isn't present.<br>
|
|
104
|
+
Check the <a href="${docsBaseUrl}packagejson/" target=_blank><code>package.json</code> documentation</a> for further information.`
|
|
105
|
+
},
|
|
106
|
+
'GS001-DEPR-LABS-MEMBERS': {
|
|
107
|
+
level: 'warning',
|
|
108
|
+
rule: 'The <code>{{@labs.members}}</code> helper should not be used.',
|
|
109
|
+
details: oneLineTrim`Remove <code>{{@labs.members}}</code> from the theme.<br>
|
|
110
|
+
The <code>{{@labs.members}}</code> helper will always return <code>true</code> in Ghost v4 and will be removed from Ghost v5, at which point it will return <code>null</code> and evaluate to <code>false</code>.
|
|
111
|
+
Find more information about the <code>@labs</code> property <a href="${docsBaseUrl}helpers/labs/" target=_blank>here</a>.`,
|
|
112
|
+
regex: /@labs\.members/g,
|
|
113
|
+
helper: '{{@labs.members}}'
|
|
114
|
+
},
|
|
115
|
+
'GS080-FEACH-POSTS': {
|
|
116
|
+
level: 'warning',
|
|
117
|
+
rule: 'The default visibility for posts in <code>{{#foreach}}</code> block helper has changed in v4.',
|
|
118
|
+
details: oneLineTrim`The default visibility for posts in <code>{{#foreach}}</code> block helper has changed from <code>public</code> to <code>all</code> in Ghost v4.
|
|
119
|
+
Find more information about the <code>{{foreach}}</code> helper <a href="${docsBaseUrl}helpers/foreach/" target=_blank>here</a>.`,
|
|
120
|
+
regex: /{{\s*?#foreach\s*?\w*?\s*?}}/g,
|
|
121
|
+
helper: '{{#foreach}}',
|
|
122
|
+
validInAPI: ['v3']
|
|
123
|
+
},
|
|
124
|
+
'GS080-CARD-LAST4': {
|
|
125
|
+
level: 'warning',
|
|
126
|
+
rule: 'The <code>default_payment_card_last4</code> field now coalesces to <code>****</code> in Ghost 4.x instead of null.',
|
|
127
|
+
details: oneLineTrim`The <code>default_payment_card_last4</code> field no longer outputs a falsy(null) value in case of missing card details starting from Ghost 4.x and instead coalesces to <code>****</code>
|
|
128
|
+
Find more information about the <code>default_payment_card_last4</code> attribute <a href="${docsBaseUrl}members/#subscription-attributes" target=_blank>here</a>.`,
|
|
129
|
+
regex: /default_payment_card_last4/g,
|
|
130
|
+
helper: '{{default_payment_card_last4}}',
|
|
131
|
+
validInAPI: ['v3']
|
|
132
|
+
},
|
|
133
|
+
'GS080-FEACH-PV': {
|
|
134
|
+
level: 'recommendation',
|
|
135
|
+
rule: 'The use of <code>visibility="all"</code> is no longer required for posts in <code>{{#foreach}}</code> helper.',
|
|
136
|
+
details: oneLineTrim`The default visibility in <code>{{#foreach}}</code> helper for posts has changed in v4 from "public" to "all" and is no longer required when looping over posts.
|
|
137
|
+
Check out the documentation for <code>{{#foreach}}</code> <a href="${docsBaseUrl}helpers/foreach/" target=_blank>here</a>.`,
|
|
138
|
+
regex: /{{\s*?#foreach\b[\w\s='"]*?visibility=("|')all("|')[\w\s='"]*?}}/g,
|
|
139
|
+
helper: '{{#foreach}}',
|
|
140
|
+
validInAPI: ['v3']
|
|
141
|
+
},
|
|
142
|
+
'GS001-DEPR-CURR-SYM': {
|
|
143
|
+
level: 'warning',
|
|
144
|
+
rule: 'Replace <code>{{[#].currency_symbol}}</code> with <code>{{price currency=currency}}</code>.',
|
|
145
|
+
details: oneLineTrim`The hardcoded <code>currency_symbol</code> attribute was removed in favour of passing the currency to updated <code>{{price}}</code> helper.
|
|
146
|
+
Find more information about the updated <code>{{price}}</code> helper <a href="${docsBaseUrl}members/#the-price-helper" target=_blank>here</a>.`,
|
|
147
|
+
helper: '{{[#].currency_symbol}}',
|
|
148
|
+
regex: /currency_symbol/g
|
|
149
|
+
},
|
|
150
|
+
'GS001-DEPR-SITE-LANG': {
|
|
151
|
+
level: 'warning',
|
|
152
|
+
rule: 'The <code>{{@site.lang}}</code> helper should be replaced with <code>{{@site.locale}}</code>',
|
|
153
|
+
details: oneLineTrim`Replace <code>{{@site.lang}}</code> helper with <code>{{@site.locale}}</code>.<br>
|
|
154
|
+
The <code>{{@site.lang}}</code> helper will be removed in next version of Ghost and should not be used.
|
|
155
|
+
Find more information about the <code>@site</code> property <a href="${docsBaseUrl}helpers/site/" target=_blank>here</a>.`,
|
|
156
|
+
regex: /@site\.lang/g,
|
|
157
|
+
helper: '{{@site.lang}}'
|
|
158
|
+
},
|
|
159
|
+
'GS070-VALID-TRANSLATIONS': {
|
|
160
|
+
level: 'error',
|
|
161
|
+
rule: 'Theme translations must be parsable',
|
|
162
|
+
fatal: true, // overwritten from v3 to be fatal
|
|
163
|
+
details: oneLineTrim`Theme translations (located in <code>locales/*.json</code>) need to be readable by the node JSON parser, or they will not be applied.`
|
|
164
|
+
},
|
|
165
|
+
'GS090-NO-IMG-URL-IN-CONDITIONALS': {
|
|
166
|
+
level: 'warning',
|
|
167
|
+
rule: 'The {{img_url}} helper should not be used as a parameter to {{#if}} or {{#unless}}',
|
|
168
|
+
fatal: false,
|
|
169
|
+
details: oneLineTrim`The {{img_url}} helper should not be used as a parameter to {{#if}} or {{#unless}}`
|
|
170
|
+
},
|
|
171
|
+
'GS090-NO-UNKNOWN-CUSTOM-THEME-SETTINGS': {
|
|
172
|
+
level: 'error',
|
|
173
|
+
rule: 'An unkown custom theme setting has been used.',
|
|
174
|
+
fatal: false,
|
|
175
|
+
details: oneLineTrim`The custom theme setting should all be defined in the package.json <code>config.custom</code> object.`
|
|
176
|
+
},
|
|
177
|
+
'GS090-NO-UNKNOWN-CUSTOM-THEME-SELECT-VALUE-IN-MATCH': {
|
|
178
|
+
level: 'error',
|
|
179
|
+
rule: 'A custom theme setting of type <code>select</code> has been compared to a value that isn\'t defined.',
|
|
180
|
+
fatal: false,
|
|
181
|
+
details: oneLineTrim`Custom theme settings of type <code>select</code> can only be compared to their defined <code>options</code> when used in a <code>match</code> block.`
|
|
182
|
+
},
|
|
183
|
+
'GS100-NO-UNUSED-CUSTOM-THEME-SETTING': {
|
|
184
|
+
level: 'error',
|
|
185
|
+
rule: 'A custom theme setting defined in <code>package.json</code> hasn\'t been used in any theme file.',
|
|
186
|
+
details: oneLineTrim`Custom theme settings defined in <code>package.json</code> must be used at least once in the theme templates.`
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
'GS050-CSS-KGCO': cssCardRule('callout', 'kg-callout-card'),
|
|
190
|
+
'GS050-CSS-KGCOE': cssCardRule('callout', 'kg-callout-card-emoji'),
|
|
191
|
+
'GS050-CSS-KGCOT': cssCardRule('callout', 'kg-callout-card-text'),
|
|
192
|
+
'GS050-CSS-KGCOBGGY': cssCardRule('callout', 'kg-callout-card-background-grey'),
|
|
193
|
+
'GS050-CSS-KGCOBGW': cssCardRule('callout', 'kg-callout-card-background-white'),
|
|
194
|
+
'GS050-CSS-KGCOBGB': cssCardRule('callout', 'kg-callout-card-background-blue'),
|
|
195
|
+
'GS050-CSS-KGCOBGGN': cssCardRule('callout', 'kg-callout-card-background-green'),
|
|
196
|
+
'GS050-CSS-KGCOBGY': cssCardRule('callout', 'kg-callout-card-background-yellow'),
|
|
197
|
+
'GS050-CSS-KGCOBGR': cssCardRule('callout', 'kg-callout-card-background-red'),
|
|
198
|
+
'GS050-CSS-KGCOBGPK': cssCardRule('callout', 'kg-callout-card-background-pink'),
|
|
199
|
+
'GS050-CSS-KGCOBGPE': cssCardRule('callout', 'kg-callout-card-background-purple'),
|
|
200
|
+
'GS050-CSS-KGCOBGA': cssCardRule('callout', 'kg-callout-card-background-accent'),
|
|
201
|
+
|
|
202
|
+
'GS050-CSS-KG-NFT': cssCardRule('nft', 'kg-nft-card'),
|
|
203
|
+
'GS050-CSS-KG-NFTCO': cssCardRule('nft', 'kg-nft-card-container'),
|
|
204
|
+
'GS050-CSS-KG-NFTMD': cssCardRule('nft', 'kg-nft-metadata'),
|
|
205
|
+
'GS050-CSS-KG-NFTIMG': cssCardRule('nft', 'kg-nft-image'),
|
|
206
|
+
'GS050-CSS-KG-NFTHD': cssCardRule('nft', 'kg-nft-header'),
|
|
207
|
+
'GS050-CSS-KG-NFTTIT': cssCardRule('nft', 'kg-nft-title'),
|
|
208
|
+
'GS050-CSS-KG-NFTLG': cssCardRule('nft', 'kg-nft-logo'),
|
|
209
|
+
'GS050-CSS-KG-NFTCTR': cssCardRule('nft', 'kg-nft-creator'),
|
|
210
|
+
'GS050-CSS-KG-NFTDSC': cssCardRule('nft', 'kg-nft-description'),
|
|
211
|
+
|
|
212
|
+
'GS050-CSS-KGTGL': cssCardRule('toggle', 'kg-toggle-card'),
|
|
213
|
+
'GS050-CSS-KGTGLH': cssCardRule('toggle', 'kg-toggle-heading'),
|
|
214
|
+
'GS050-CSS-KGTGLHT': cssCardRule('toggle', 'kg-toggle-heading-text'),
|
|
215
|
+
'GS050-CSS-KGTGLIC': cssCardRule('toggle', 'kg-toggle-card-icon'),
|
|
216
|
+
'GS050-CSS-KGTGLC': cssCardRule('toggle', 'kg-toggle-content'),
|
|
217
|
+
|
|
218
|
+
'GS050-CSS-KGAUD': cssCardRule('audio', 'kg-audio-card'),
|
|
219
|
+
'GS050-CSS-KGAUDTHUMB': cssCardRule('audio', 'kg-audio-thumbnail'),
|
|
220
|
+
'GS050-CSS-KGAUDTHUMBPL': cssCardRule('audio', 'kg-audio-thumbnail.placeholder'),
|
|
221
|
+
'GS050-CSS-KGAUDPLCNT': cssCardRule('audio', 'kg-audio-player-container'),
|
|
222
|
+
'GS050-CSS-KGAUDTI': cssCardRule('audio', 'kg-audio-title'),
|
|
223
|
+
'GS050-CSS-KGAUDPL': cssCardRule('audio', 'kg-audio-player'),
|
|
224
|
+
'GS050-CSS-KGAUDCURRTM': cssCardRule('audio', 'kg-audio-current-time'),
|
|
225
|
+
'GS050-CSS-KGAUDTM': cssCardRule('audio', 'kg-audio-time'),
|
|
226
|
+
'GS050-CSS-KGAUDDUR': cssCardRule('audio', 'kg-audio-duration'),
|
|
227
|
+
'GS050-CSS-KGAUDPLICO': cssCardRule('audio', 'kg-audio-play-icon'),
|
|
228
|
+
'GS050-CSS-KGAUDPAUICO': cssCardRule('audio', 'kg-audio-pause-icon'),
|
|
229
|
+
'GS050-CSS-KGAUDSKSL': cssCardRule('audio', 'kg-audio-seek-slider'),
|
|
230
|
+
'GS050-CSS-KGAUDPLRT': cssCardRule('audio', 'kg-audio-playback-rate'),
|
|
231
|
+
'GS050-CSS-KGAUDMTICO': cssCardRule('audio', 'kg-audio-mute-icon'),
|
|
232
|
+
'GS050-CSS-KGAUDUNMTICO': cssCardRule('audio', 'kg-audio-unmute-icon'),
|
|
233
|
+
'GS050-CSS-KGAUDVOLSL': cssCardRule('audio', 'kg-audio-volume-slider'),
|
|
234
|
+
|
|
235
|
+
'GS050-CSS-KGVID': cssCardRule('video', 'kg-video-card'),
|
|
236
|
+
'GS050-CSS-KGVIDHD': cssCardRule('video', 'kg-video-hide'),
|
|
237
|
+
'GS050-CSS-KGVIDCNT': cssCardRule('video', 'kg-video-container'),
|
|
238
|
+
'GS050-CSS-KGVIDOVL': cssCardRule('video', 'kg-video-overlay'),
|
|
239
|
+
'GS050-CSS-KGVIDLGPLICO': cssCardRule('video', 'kg-video-large-play-icon'),
|
|
240
|
+
'GS050-CSS-KGVIDTHUMB': cssCardRule('video', 'kg-video-thumbnail'),
|
|
241
|
+
'GS050-CSS-KGVIDTHUMBPL': cssCardRule('video', 'kg-video-thumbnail.placeholder'),
|
|
242
|
+
'GS050-CSS-KGVIDPLCNT': cssCardRule('video', 'kg-video-player-container'),
|
|
243
|
+
'GS050-CSS-KGVIDTI': cssCardRule('video', 'kg-video-title'),
|
|
244
|
+
'GS050-CSS-KGVIDPL': cssCardRule('video', 'kg-video-player'),
|
|
245
|
+
'GS050-CSS-KGVIDCURRTM': cssCardRule('video', 'kg-video-current-time'),
|
|
246
|
+
'GS050-CSS-KGVIDTM': cssCardRule('video', 'kg-video-time'),
|
|
247
|
+
'GS050-CSS-KGVIDDUR': cssCardRule('video', 'kg-video-duration'),
|
|
248
|
+
'GS050-CSS-KGVIDPLICO': cssCardRule('video', 'kg-video-play-icon'),
|
|
249
|
+
'GS050-CSS-KGVIDPAUICO': cssCardRule('video', 'kg-video-pause-icon'),
|
|
250
|
+
'GS050-CSS-KGVIDSKSL': cssCardRule('video', 'kg-video-seek-slider'),
|
|
251
|
+
'GS050-CSS-KGVIDPLRT': cssCardRule('video', 'kg-video-playback-rate'),
|
|
252
|
+
'GS050-CSS-KGVIDMTICO': cssCardRule('video', 'kg-video-mute-icon'),
|
|
253
|
+
'GS050-CSS-KGVIDUNMTICO': cssCardRule('video', 'kg-video-unmute-icon'),
|
|
254
|
+
'GS050-CSS-KGVIDVOLSL': cssCardRule('video', 'kg-video-volume-slider'),
|
|
255
|
+
|
|
256
|
+
'GS050-CSS-KGBTN': cssCardRule('button', 'kg-button-card'),
|
|
257
|
+
'GS050-CSS-KGBTNL': cssCardRule('button', 'kg-button-card.kg-align-left'),
|
|
258
|
+
'GS050-CSS-KGBTNC': cssCardRule('button', 'kg-button-card.kg-align-center'),
|
|
259
|
+
'GS050-CSS-KGBTNBTN': cssCardRule('button', 'kg-btn'),
|
|
260
|
+
'GS050-CSS-KGBTNBTNA': cssCardRule('button', 'kg-btn-accent'),
|
|
261
|
+
|
|
262
|
+
'GS050-CSS-KGPR': cssCardRule('product', 'kg-product-card'),
|
|
263
|
+
'GS050-CSS-KGPRBTNA': cssCardRule('product', 'kg-product-card-btn-accent'),
|
|
264
|
+
'GS050-CSS-KGPRBTN': cssCardRule('product', 'kg-product-card-button'),
|
|
265
|
+
'GS050-CSS-KGPRCO': cssCardRule('product', 'kg-product-card-container'),
|
|
266
|
+
'GS050-CSS-KGPRDE': cssCardRule('product', 'kg-product-card-description'),
|
|
267
|
+
'GS050-CSS-KGPRIM': cssCardRule('product', 'kg-product-card-image'),
|
|
268
|
+
'GS050-CSS-KGPRRA': cssCardRule('product', 'kg-product-card-rating'),
|
|
269
|
+
'GS050-CSS-KGPRRAA': cssCardRule('product', 'kg-product-card-rating-active'),
|
|
270
|
+
'GS050-CSS-KGPRRAS': cssCardRule('product', 'kg-product-card-rating-star'),
|
|
271
|
+
'GS050-CSS-KGPRTI': cssCardRule('product', 'kg-product-card-title'),
|
|
272
|
+
'GS050-CSS-KGPRTICO': cssCardRule('product', 'kg-product-card-title-container'),
|
|
273
|
+
|
|
274
|
+
'GS050-CSS-KGBA': cssCardRule('before-after', 'kg-before-after-card'),
|
|
275
|
+
'GS050-CSS-KGBAIA': cssCardRule('before-after', 'kg-before-after-card-image-before'),
|
|
276
|
+
'GS050-CSS-KGBAIB': cssCardRule('before-after', 'kg-before-after-card-image-after'),
|
|
277
|
+
|
|
278
|
+
'GS050-CSS-KGFL': cssCardRule('file', 'kg-file-card'),
|
|
279
|
+
'GS050-CSS-KGFLCON': cssCardRule('file', 'kg-file-card-container'),
|
|
280
|
+
'GS050-CSS-KGFLCNT': cssCardRule('file', 'kg-file-card-contents'),
|
|
281
|
+
'GS050-CSS-KGFLTTL': cssCardRule('file', 'kg-file-card-title'),
|
|
282
|
+
'GS050-CSS-KGFLCAP': cssCardRule('file', 'kg-file-card-caption'),
|
|
283
|
+
'GS050-CSS-KGFLNM': cssCardRule('file', 'kg-file-card-filename'),
|
|
284
|
+
'GS050-CSS-KGFLSZ': cssCardRule('file', 'kg-file-card-filesize'),
|
|
285
|
+
'GS050-CSS-KGFLMD': cssCardRule('file', 'kg-file-card-medium'),
|
|
286
|
+
'GS050-CSS-KGFLSM': cssCardRule('file', 'kg-file-card-small'),
|
|
287
|
+
|
|
288
|
+
'GS050-CSS-KGBQALT': cssCardRule('blockquote', 'kg-blockquote-alt')
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
knownHelpers = _.union(previousKnownHelpers, knownHelpers);
|
|
292
|
+
templates = _.union(previousTemplates, templates);
|
|
293
|
+
|
|
294
|
+
// Merge the previous rules into the new rules, but overwrite any specified property,
|
|
295
|
+
// as well as adding any new rule to the spec.
|
|
296
|
+
// Furthermore, replace the usage of the old doc URLs that we're linking to, with the
|
|
297
|
+
// new version.
|
|
298
|
+
rules = _.each(_.merge({}, previousRules, rules), function replaceDocsUrl(value) {
|
|
299
|
+
value.details = value.details.replace(prevDocsBaseUrlRegEx, docsBaseUrl);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
module.exports = {
|
|
303
|
+
knownHelpers: knownHelpers,
|
|
304
|
+
templates: templates,
|
|
305
|
+
rules: rules
|
|
306
|
+
};
|
package/lib/utils/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Makes sure the paths are forward-slash-separated `/`
|
|
3
3
|
* This is needed because the partial are only referenced with forward-slashes
|
|
4
4
|
* in Handlebars templates.
|
|
5
|
-
* @param {string} path
|
|
5
|
+
* @param {string} path filesystem path
|
|
6
6
|
* @returns {string} the linux-normalized path
|
|
7
7
|
*/
|
|
8
8
|
function normalizePath(path) {
|
package/lib/utils/versions.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gscan",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.23.0",
|
|
4
4
|
"description": "Scans Ghost themes looking for errors, deprecations, features and compatibility",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ghost",
|
|
@@ -29,31 +29,31 @@
|
|
|
29
29
|
"scripts": {
|
|
30
30
|
"start": "node app/index.js",
|
|
31
31
|
"dev": "NODE_ENV=development DEBUG=gscan:* nodemon",
|
|
32
|
-
"lint": "eslint
|
|
32
|
+
"lint": "eslint ./app --ext .js --cache",
|
|
33
33
|
"test": "NODE_ENV=testing mocha -- $(find test -name '*.test.js')",
|
|
34
34
|
"posttest": "yarn lint",
|
|
35
35
|
"coverage": "NODE_ENV=testing istanbul cover --dir test/coverage _mocha -- $(find test -name '*.test.js')",
|
|
36
36
|
"preship": "yarn test",
|
|
37
|
-
"ship": "
|
|
37
|
+
"ship": "yarn publish && git push ${GHOST_UPSTREAM:-upstream} main --follow-tags"
|
|
38
38
|
},
|
|
39
39
|
"bin": {
|
|
40
40
|
"gscan": "./bin/cli.js"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@sentry/node": "6.
|
|
43
|
+
"@sentry/node": "6.18.2",
|
|
44
44
|
"@tryghost/config": "0.2.2",
|
|
45
|
-
"@tryghost/debug": "0.1.
|
|
45
|
+
"@tryghost/debug": "0.1.11",
|
|
46
46
|
"@tryghost/ignition-errors": "0.1.8",
|
|
47
|
-
"@tryghost/logging": "2.0.
|
|
48
|
-
"@tryghost/pretty-cli": "1.2.
|
|
47
|
+
"@tryghost/logging": "2.0.4",
|
|
48
|
+
"@tryghost/pretty-cli": "1.2.24",
|
|
49
49
|
"@tryghost/server": "0.1.4",
|
|
50
|
-
"@tryghost/zip": "1.1.
|
|
50
|
+
"@tryghost/zip": "1.1.20",
|
|
51
51
|
"bluebird": "3.7.2",
|
|
52
52
|
"chalk": "4.1.2",
|
|
53
53
|
"common-tags": "1.8.2",
|
|
54
|
-
"express": "4.17.
|
|
54
|
+
"express": "4.17.3",
|
|
55
55
|
"express-hbs": "2.4.0",
|
|
56
|
-
"fs-extra": "
|
|
56
|
+
"fs-extra": "10.0.1",
|
|
57
57
|
"glob": "7.2.0",
|
|
58
58
|
"lodash": "4.17.21",
|
|
59
59
|
"multer": "1.4.4",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"nodemon": "2.0.7",
|
|
72
72
|
"rewire": "6.0.0",
|
|
73
73
|
"should": "13.2.3",
|
|
74
|
-
"sinon": "
|
|
74
|
+
"sinon": "13.0.0"
|
|
75
75
|
},
|
|
76
76
|
"files": [
|
|
77
77
|
"lib",
|