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.
@@ -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
  {},
@@ -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, themePath) {
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
- theme.files.forEach(function (themeFile) {
36
- try {
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: 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, file) {
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
- // NOTE: lstat does not follow symlinks
64
- return fs.lstat(newPath).then(function (statFile) {
65
- if (statFile.isDirectory()) {
66
- return readThemeStructure(newPath, subFilePath, result);
67
- } else {
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
  };
@@ -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/api/handlebars-themes/`;
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/data/" target=_blank>here</a>.`,
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, // @TODO (major): mark as fatal
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/api/handlebars-themes/`;
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.25.3",
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.2",
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",