gscan 4.25.3 → 4.26.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/lib/checks/010-package-json.js +3 -0
- package/lib/checks/030-assets.js +5 -17
- package/lib/read-theme.js +11 -12
- package/lib/specs/canary.js +137 -1
- package/lib/specs/v2.js +1 -1
- package/lib/specs/v3.js +1 -1
- package/lib/specs/v4.js +1 -1
- package/package.json +2 -2
|
@@ -261,7 +261,10 @@ module.exports = function checkPackageJSON(theme, options) {
|
|
|
261
261
|
v4PackageJSONValidationRules,
|
|
262
262
|
canaryPackageJSONValidationRules
|
|
263
263
|
);
|
|
264
|
+
// Make these delete more declarative as the list grows
|
|
264
265
|
delete packageJSONValidationRules.isNotPresentEngineGhostAPI;
|
|
266
|
+
delete packageJSONValidationRules.isv01EngineGhostAPI;
|
|
267
|
+
delete packageJSONValidationRules.isv2EngineGhostAPI;
|
|
265
268
|
|
|
266
269
|
packageJSONConditionalRules = _.merge(
|
|
267
270
|
{},
|
package/lib/checks/030-assets.js
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const fs = require('fs');
|
|
4
2
|
const spec = require('../specs');
|
|
5
3
|
const versions = require('../utils').versions;
|
|
6
4
|
|
|
7
|
-
const checkAssets = function checkAssets(theme, options
|
|
5
|
+
const checkAssets = function checkAssets(theme, options) {
|
|
8
6
|
const checkVersion = _.get(options, 'checkVersion', versions.default);
|
|
9
7
|
const ruleSet = spec.get([checkVersion]);
|
|
10
8
|
|
|
11
9
|
let ruleToCheck = 'GS030-ASSET-REQ';
|
|
12
10
|
let failures = [];
|
|
13
11
|
let assetMatch;
|
|
14
|
-
let stats;
|
|
15
12
|
|
|
16
13
|
_.filter(theme.files, {ext: '.hbs'}).forEach(function (template) {
|
|
17
14
|
try {
|
|
@@ -30,19 +27,10 @@ const checkAssets = function checkAssets(theme, options, themePath) {
|
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
ruleToCheck = 'GS030-ASSET-SYM';
|
|
33
|
-
failures =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
stats = fs.lstatSync(path.join(themePath, themeFile.file));
|
|
38
|
-
|
|
39
|
-
if (stats.isSymbolicLink()) {
|
|
40
|
-
failures.push({ref: themeFile.file});
|
|
41
|
-
}
|
|
42
|
-
} catch (err) {
|
|
43
|
-
// ignore
|
|
44
|
-
}
|
|
45
|
-
});
|
|
30
|
+
failures = theme
|
|
31
|
+
.files
|
|
32
|
+
.filter(f => f.symlink)
|
|
33
|
+
.map(f => ({ref: f.file}));
|
|
46
34
|
|
|
47
35
|
if (failures.length > 0) {
|
|
48
36
|
theme.results.fail[ruleToCheck] = {failures: failures};
|
package/lib/read-theme.js
CHANGED
|
@@ -29,16 +29,18 @@ const readThemeStructure = function readThemeFiles(themePath, subPath, arr) {
|
|
|
29
29
|
|
|
30
30
|
arr = arr || [];
|
|
31
31
|
|
|
32
|
-
var makeResult = function makeResult(result, subFilePath, ext) {
|
|
32
|
+
var makeResult = function makeResult(result, subFilePath, ext, symlink) {
|
|
33
33
|
result.push({
|
|
34
34
|
file: subFilePath,
|
|
35
|
-
ext
|
|
35
|
+
ext,
|
|
36
|
+
symlink
|
|
36
37
|
});
|
|
37
38
|
return result;
|
|
38
39
|
};
|
|
39
40
|
|
|
40
|
-
return fs.readdir(themePath).then(function (files) {
|
|
41
|
-
return Promise.reduce(files, function (result,
|
|
41
|
+
return fs.readdir(themePath, {withFileTypes: true}).then(function (files) {
|
|
42
|
+
return Promise.reduce(files, function (result, dirent) {
|
|
43
|
+
const file = dirent.name;
|
|
42
44
|
var extMatch = file.match(/.*?(\.[0-9a-z]+$)/i),
|
|
43
45
|
subFilePath = path.join(subPath, file),
|
|
44
46
|
newPath = path.join(themePath, file);
|
|
@@ -60,14 +62,11 @@ const readThemeStructure = function readThemeFiles(themePath, subPath, arr) {
|
|
|
60
62
|
: result;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return makeResult(result, subFilePath, extMatch !== null ? extMatch[1] : undefined);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
65
|
+
if (dirent.isDirectory()) {
|
|
66
|
+
return readThemeStructure(newPath, subFilePath, result);
|
|
67
|
+
} else {
|
|
68
|
+
return makeResult(result, subFilePath, extMatch !== null ? extMatch[1] : undefined, dirent.isSymbolicLink());
|
|
69
|
+
}
|
|
71
70
|
}, arr);
|
|
72
71
|
});
|
|
73
72
|
};
|
package/lib/specs/canary.js
CHANGED
|
@@ -2,7 +2,7 @@ const _ = require('lodash');
|
|
|
2
2
|
const oneLineTrim = require('common-tags/lib/oneLineTrim');
|
|
3
3
|
const previousSpec = require('./v4');
|
|
4
4
|
const ghostVersions = require('../utils').versions;
|
|
5
|
-
const docsBaseUrl = `https://ghost.org/docs/
|
|
5
|
+
const docsBaseUrl = `https://ghost.org/docs/themes/`;
|
|
6
6
|
const prevDocsBaseUrl = `https://themes.ghost.org/v${ghostVersions.v5.docs}/docs/`;
|
|
7
7
|
const prevDocsBaseUrlRegEx = new RegExp(prevDocsBaseUrl, 'g');
|
|
8
8
|
|
|
@@ -423,6 +423,51 @@ let rules = {
|
|
|
423
423
|
regex: /{{\s*?post\.author\.cover\s*?}}/g,
|
|
424
424
|
helper: '{{post.author.cover}}'
|
|
425
425
|
},
|
|
426
|
+
'GS001-DEPR-AUTH-INCL': {
|
|
427
|
+
level: 'error',
|
|
428
|
+
fatal: true,
|
|
429
|
+
rule: `<code>include="author"</code> should be replaced with <code>include="authors"</code>`,
|
|
430
|
+
details: oneLineTrim`The usage of <code>{{#get "posts" include="author"}}</code> is deprecated and should be replaced with <code>{{#get "posts" include="authors"}}</code>.<br>
|
|
431
|
+
Find more information about the <code>{{get}}</code> helper <a href="${docsBaseUrl}helpers/get/" target=_blank>here</a>.`,
|
|
432
|
+
// This regex seems only to work properly with the escaped characters. Removing them resulted
|
|
433
|
+
// in not detecting the wrong usage.
|
|
434
|
+
regex: /{{\s*?#get.+include=("|')\s*?([\w\[\]]+,{1}\s*?)*?(\s*?author\s*?)(\s*,{1}\s?[\w\[\]]+)*?\s*?("|')(.*)}}/g, // eslint-disable-line no-useless-escape
|
|
435
|
+
helper: 'include="author"'
|
|
436
|
+
},
|
|
437
|
+
'GS001-DEPR-AUTH-FIELD': {
|
|
438
|
+
level: 'error',
|
|
439
|
+
fatal: true,
|
|
440
|
+
rule: `<code>fields="author"</code> should be replaced with <code>fields="authors"</code>`,
|
|
441
|
+
details: oneLineTrim`The usage of <code>{{#get "posts" fields="author"}}</code> is deprecated and should be replaced with
|
|
442
|
+
<code>{{#get "posts" fields="primary_author"}}</code> or <code>{{#get "posts" fields="authors.[#]"}}</code>.<br>
|
|
443
|
+
Find more information about the <code>{{get}}</code> helper <a href="${docsBaseUrl}helpers/get/" target=_blank>here</a>.`,
|
|
444
|
+
// This regex seems only to work properly with the escaped characters. Removing them resulted
|
|
445
|
+
// in not detecting the wrong usage.
|
|
446
|
+
regex: /{{\s*?#get.+fields=("|')\s*?([\w\[\]]+,{1}\s*?)*?(\s*?author\s*?)(\s*,{1}\s?[\w\[\]]+)*?\s*?("|')(.*)}}/g, // eslint-disable-line no-useless-escape
|
|
447
|
+
helper: 'fields="author"'
|
|
448
|
+
},
|
|
449
|
+
'GS001-DEPR-AUTH-FILT': {
|
|
450
|
+
level: 'error',
|
|
451
|
+
fatal: true,
|
|
452
|
+
rule: `<code>filter="author:[...]"</code> should be replaced with <code>filter="authors:[...]"</code>`,
|
|
453
|
+
details: oneLineTrim`The usage of <code>{{#get "posts" filter="author:[...]"}}</code> is deprecated and should be replaced with <code>{{#get "posts" filter="authors:[...]"}}</code>.<br>
|
|
454
|
+
Find more information about the <code>{{get}}</code> helper <a href="${docsBaseUrl}helpers/get/" target=_blank>here</a>.`,
|
|
455
|
+
// This regex seems only to work properly with the escaped characters. Removing them resulted
|
|
456
|
+
// in not detecting the wrong usage.
|
|
457
|
+
regex: /{{\s*?#get.+filter=("|')\s*?([\w\[\]]+,{1}\s*?)*?(\s*?author:).*("|')(.*)}}/g, // eslint-disable-line no-useless-escape
|
|
458
|
+
helper: 'filter="author:[...]"'
|
|
459
|
+
},
|
|
460
|
+
'GS001-DEPR-AUTHBL': {
|
|
461
|
+
level: 'error',
|
|
462
|
+
fatal: true,
|
|
463
|
+
rule: 'The <code>{{#author}}</code> block helper should be replaced with <code>{{#primary_author}}</code> or <code>{{#foreach authors}}...{{/foreach}}</code>',
|
|
464
|
+
details: oneLineTrim`The usage of <code>{{#author}}</code> block helper outside of <code>author.hbs</code> is deprecated and
|
|
465
|
+
should be replaced with <code>{{#primary_author}}</code> or <code>{{#foreach authors}}...{{/foreach}}</code>.<br>
|
|
466
|
+
Find more information about the <code>{{authors}}</code> helper <a href="${docsBaseUrl}helpers/authors/" target=_blank>here</a>.`,
|
|
467
|
+
regex: /{{\s*?#author\s*?}}/g,
|
|
468
|
+
notValidIn: 'author.hbs',
|
|
469
|
+
helper: '{{#author}}'
|
|
470
|
+
},
|
|
426
471
|
'GS001-DEPR-PAIMG': {
|
|
427
472
|
level: 'error',
|
|
428
473
|
fatal: true,
|
|
@@ -434,6 +479,28 @@ let rules = {
|
|
|
434
479
|
regex: /{{\s*?post\.author\.image\s*?}}/g,
|
|
435
480
|
helper: '{{post.author.image}}'
|
|
436
481
|
},
|
|
482
|
+
'GS001-DEPR-CON-AUTH': {
|
|
483
|
+
level: 'error',
|
|
484
|
+
fatal: true,
|
|
485
|
+
rule: `The <code>{{#if author.*}}</code> block helper should be replaced with <code>{{#if primary_author.*}}</code>
|
|
486
|
+
or <code>{{#if authors.[#].*}}</code>`,
|
|
487
|
+
details: oneLineTrim`The usage of <code>{{#if author.*}}</code> is deprecated and should be replaced with <code>{{#if primary_author.*}}</code>
|
|
488
|
+
or <code>{{#if authors.[#].*}}</code>.<br>
|
|
489
|
+
Find more information about the <code>{{authors}}</code> helper <a href="${docsBaseUrl}helpers/authors/" target=_blank>here</a>.`,
|
|
490
|
+
regex: /{{\s*?#if\s*?(author)(?:\.\w+)*?\s*?}}/g,
|
|
491
|
+
helper: '{{#if author.*}}'
|
|
492
|
+
},
|
|
493
|
+
'GS001-DEPR-CON-PAUTH': {
|
|
494
|
+
level: 'error',
|
|
495
|
+
fatal: true,
|
|
496
|
+
rule: `The <code>{{#if post.author.*}}</code> block helper should be replaced with <code>{{#if post.primary_author.*}}</code>
|
|
497
|
+
or <code>{{#if post.authors.[#].*}}</code>`,
|
|
498
|
+
details: oneLineTrim`The usage of <code>{{#if post.author.*}}</code> is deprecated and should be replaced with <code>{{#if post.primary_author.*}}</code>
|
|
499
|
+
or <code>{{#if post.authors.[#].*}}</code>.<br>
|
|
500
|
+
Find more information about the <code>{{authors}}</code> helper <a href="${docsBaseUrl}helpers/authors/" target=_blank>here</a>.`,
|
|
501
|
+
regex: /{{\s*?#if\s*?(?:post\.)(author)(?:\.\w+)*?\s*?}}/g,
|
|
502
|
+
helper: '{{#if post.author.*}}'
|
|
503
|
+
},
|
|
437
504
|
'GS001-DEPR-CON-AC': {
|
|
438
505
|
level: 'error',
|
|
439
506
|
fatal: true,
|
|
@@ -477,6 +544,75 @@ let rules = {
|
|
|
477
544
|
See the object attributes of <code>author</code> <a href="${docsBaseUrl}context/author/#author-object-attributes" target=_blank>here</a>.`,
|
|
478
545
|
regex: /{{\s*?#if\s*?post\.author\.image\s*?}}/g,
|
|
479
546
|
helper: '{{#if post.author.image}}'
|
|
547
|
+
},
|
|
548
|
+
'GS001-DEPR-SPL': {
|
|
549
|
+
level: 'error',
|
|
550
|
+
fatal: true,
|
|
551
|
+
rule: '<code>{{@site.permalinks}}</code> was removed',
|
|
552
|
+
details: oneLineTrim`With the introduction of Dynamic Routing, you can define multiple permalinks.<br>
|
|
553
|
+
The <code>{{@site.permalinks}}</code> property will therefore no longer be used and should be removed from the theme.
|
|
554
|
+
Find more information about the <code>@site</code> property <a href="${docsBaseUrl}helpers/site/" target=_blank>here</a>.`,
|
|
555
|
+
regex: /{{\s*?@site\.permalinks\s*?}}/g,
|
|
556
|
+
helper: '{{@site.permalinks}}'
|
|
557
|
+
},
|
|
558
|
+
'GS001-DEPR-BPL': {
|
|
559
|
+
level: 'error',
|
|
560
|
+
fatal: true,
|
|
561
|
+
rule: '<code>{{@blog.permalinks}}</code> was removed',
|
|
562
|
+
details: oneLineTrim`With the introduction of Dynamic Routing, you can define multiple permalinks.<br>
|
|
563
|
+
The <code>{{@blog.permalinks}}</code> property will therefore no longer be used and should be removed from the theme.
|
|
564
|
+
Find more information about Ghost data helpers <a href="${docsBaseUrl}/helpers/#data-helpers" target=_blank>here</a>.`,
|
|
565
|
+
regex: /{{\s*?@blog\.permalinks\s*?}}/g,
|
|
566
|
+
helper: '{{@blog.permalinks}}'
|
|
567
|
+
},
|
|
568
|
+
'GS001-DEPR-SGF': {
|
|
569
|
+
level: 'error',
|
|
570
|
+
fatal: true,
|
|
571
|
+
rule: 'Replace <code>{{@site.ghost_foot}}</code> with <code>{{ghost_foot}}</code>',
|
|
572
|
+
details: oneLineTrim`The usage of <code>{{@site.ghost_foot}}</code> is deprecated and should be replaced with <code>{{ghost_foot}}</code>.<br>
|
|
573
|
+
The <code>{{@site.ghost_foot}}</code> property will therefore no longer be used and should be removed from the theme.
|
|
574
|
+
Find more information about the <code>{{ghost_foot}}</code> property <a href="${docsBaseUrl}helpers/ghost_head_foot/" target=_blank>here</a>.`,
|
|
575
|
+
regex: /{{\s*?@site\.ghost_foot\s*?}}/g,
|
|
576
|
+
helper: '{{@site.ghost_foot}}'
|
|
577
|
+
},
|
|
578
|
+
'GS001-DEPR-SGH': {
|
|
579
|
+
level: 'error',
|
|
580
|
+
fatal: true,
|
|
581
|
+
rule: 'Replace <code>{{@site.ghost_head}}</code> with <code>{{ghost_head}}</code>',
|
|
582
|
+
details: oneLineTrim`The usage of <code>{{@site.ghost_head}}</code> is deprecated and should be replaced with <code>{{ghost_head}}</code>.<br>
|
|
583
|
+
The <code>{{@site.ghost_head}}</code> property will therefore no longer be used and should be removed from the theme.
|
|
584
|
+
Find more information about the <code>{{ghost_head}}</code> property <a href="${docsBaseUrl}helpers/ghost_head_foot/" target=_blank>here</a>.`,
|
|
585
|
+
regex: /{{\s*?@site\.ghost_head\s*?}}/g,
|
|
586
|
+
helper: '{{@site.ghost_head}}'
|
|
587
|
+
},
|
|
588
|
+
'GS001-DEPR-LANG': {
|
|
589
|
+
level: 'error',
|
|
590
|
+
fatal: true,
|
|
591
|
+
rule: 'The <code>{{lang}}</code> helper should be replaced with <code>{{@site.locale}}</code>',
|
|
592
|
+
details: oneLineTrim`Replace <code>{{lang}}</code> helper with <code>{{@site.locale}}</code>.<br>
|
|
593
|
+
The <code>{{lang}}</code> helper is removed in v5 version of Ghost and should not be used.
|
|
594
|
+
Find more information about the <code>@site.locale</code> property <a href="${docsBaseUrl}helpers/site/" target=_blank>here</a>.`,
|
|
595
|
+
regex: /{{\s*?lang\s*?}}/g,
|
|
596
|
+
helper: '{{lang}}'
|
|
597
|
+
},
|
|
598
|
+
'GS001-DEPR-SITE-LANG': {
|
|
599
|
+
level: 'error',
|
|
600
|
+
fatal: true,
|
|
601
|
+
rule: 'The <code>{{@site.lang}}</code> helper should be replaced with <code>{{@site.locale}}</code>',
|
|
602
|
+
details: oneLineTrim`Replace <code>{{@site.lang}}</code> helper with <code>{{@site.locale}}</code>.<br>
|
|
603
|
+
The <code>{{@site.lang}}</code> helper is removed in v5 version of Ghost and should not be used.
|
|
604
|
+
Find more information about the <code>@site.locale</code> property <a href="${docsBaseUrl}helpers/site/" target=_blank>here</a>.`,
|
|
605
|
+
regex: /@site\.lang/g,
|
|
606
|
+
helper: '{{@site.lang}}'
|
|
607
|
+
},
|
|
608
|
+
'GS001-DEPR-USER-GET': {
|
|
609
|
+
level: 'error',
|
|
610
|
+
fatal: true,
|
|
611
|
+
rule: `<code>{{#get "users"}}</code> should be replaced with <code>{{#get "authors"}}</code>`,
|
|
612
|
+
details: oneLineTrim`The usage of <code>{{#get "users"}}</code> is deprecated and will not return any data. It should be replaced with <code>{{#get "authors"}}</code>.<br>
|
|
613
|
+
Find more information about the <code>{{get}}</code> helper <a href="${docsBaseUrl}helpers/get/" target=_blank>here</a>.`,
|
|
614
|
+
regex: /{{\s*?#get ("|')\s*users("|')\s*/g,
|
|
615
|
+
helper: '{{#get "users"}}'
|
|
480
616
|
}
|
|
481
617
|
};
|
|
482
618
|
|
package/lib/specs/v2.js
CHANGED
|
@@ -403,7 +403,7 @@ let rules = {
|
|
|
403
403
|
rule: '<code>{{@blog.permalinks}}</code> was removed',
|
|
404
404
|
details: oneLineTrim`With the introduction of Dynamic Routing, you can define multiple permalinks.<br>
|
|
405
405
|
The <code>{{@blog.permalinks}}</code> property will therefore no longer be used and should be removed from the theme.
|
|
406
|
-
Find more information about Ghost data helpers <a href="${docsBaseUrl}/helpers
|
|
406
|
+
Find more information about Ghost data helpers <a href="${docsBaseUrl}/helpers/#data-helpers" target=_blank>here</a>.`,
|
|
407
407
|
regex: /{{\s*?@blog\.permalinks\s*?}}/g,
|
|
408
408
|
helper: '{{@blog.permalinks}}'
|
|
409
409
|
},
|
package/lib/specs/v3.js
CHANGED
|
@@ -49,7 +49,7 @@ let rules = {
|
|
|
49
49
|
'GS070-VALID-TRANSLATIONS': {
|
|
50
50
|
level: 'error',
|
|
51
51
|
rule: 'Theme translations must be parsable',
|
|
52
|
-
fatal: false,
|
|
52
|
+
fatal: false,
|
|
53
53
|
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.`
|
|
54
54
|
}
|
|
55
55
|
};
|
package/lib/specs/v4.js
CHANGED
|
@@ -2,7 +2,7 @@ const _ = require('lodash');
|
|
|
2
2
|
const oneLineTrim = require('common-tags/lib/oneLineTrim');
|
|
3
3
|
const previousSpec = require('./v3');
|
|
4
4
|
const ghostVersions = require('../utils').versions;
|
|
5
|
-
const docsBaseUrl = `https://ghost.org/docs/
|
|
5
|
+
const docsBaseUrl = `https://ghost.org/docs/themes/`;
|
|
6
6
|
const prevDocsBaseUrl = `https://themes.ghost.org/v${ghostVersions.v3.docs}/docs/`;
|
|
7
7
|
const prevDocsBaseUrlRegEx = new RegExp(prevDocsBaseUrl, 'g');
|
|
8
8
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gscan",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.26.0",
|
|
4
4
|
"description": "Scans Ghost themes looking for errors, deprecations, features and compatibility",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ghost",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"gscan": "./bin/cli.js"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@sentry/node": "6.19.
|
|
43
|
+
"@sentry/node": "6.19.3",
|
|
44
44
|
"@tryghost/config": "0.2.2",
|
|
45
45
|
"@tryghost/debug": "0.1.11",
|
|
46
46
|
"@tryghost/errors": "1.2.7",
|