gscan 4.20.2 → 4.21.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/LICENSE +1 -1
- package/README.md +1 -1
- package/app/public/android-chrome-192x192.png +0 -0
- package/app/public/android-chrome-256x256.png +0 -0
- package/app/public/apple-touch-icon.png +0 -0
- package/app/public/favicon-16x16.png +0 -0
- package/app/public/favicon-32x32.png +0 -0
- package/app/public/favicon.ico +0 -0
- package/app/public/mstile-150x150.png +0 -0
- package/app/public/safari-pinned-tab.svg +28 -0
- package/app/tpl/layouts/default.hbs +6 -1
- package/lib/ast-linter/linter.js +14 -6
- package/lib/ast-linter/rules/base.js +41 -3
- package/lib/ast-linter/rules/lint-no-unknown-partials.js +22 -4
- package/lib/ast-linter/rules/mark-declared-inline-partials.js +26 -0
- package/lib/checks/005-template-compile.js +16 -0
- package/package.json +5 -5
- package/app/public/favicon.png +0 -0
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -114,4 +114,4 @@ gscan.checkZip({
|
|
|
114
114
|
|
|
115
115
|
# Copyright & License
|
|
116
116
|
|
|
117
|
-
Copyright (c) 2013-
|
|
117
|
+
Copyright (c) 2013-2022 Ghost Foundation - Released under the [MIT license](LICENSE). Ghost and the Ghost Logo are trademarks of Ghost Foundation Ltd. Please see our [trademark policy](https://ghost.org/trademark/) for info on acceptable usage.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<?xml version="1.0" standalone="no"?>
|
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
|
3
|
+
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
|
4
|
+
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
|
5
|
+
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
|
|
6
|
+
preserveAspectRatio="xMidYMid meet">
|
|
7
|
+
<metadata>
|
|
8
|
+
Created by potrace 1.14, written by Peter Selinger 2001-2017
|
|
9
|
+
</metadata>
|
|
10
|
+
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
|
11
|
+
fill="#000000" stroke="none">
|
|
12
|
+
<path d="M2175 5114 c-710 -35 -1152 -142 -1481 -359 -397 -263 -605 -746
|
|
13
|
+
-674 -1565 -6 -69 -13 -285 -17 -480 -15 -925 66 -1475 278 -1881 276 -527
|
|
14
|
+
827 -767 1884 -820 251 -13 845 -7 1055 11 1085 90 1560 424 1770 1245 99 387
|
|
15
|
+
138 839 127 1465 -11 582 -55 933 -158 1255 -179 562 -504 859 -1106 1011
|
|
16
|
+
-200 50 -401 82 -673 105 -123 10 -867 20 -1005 13z m530 -604 c371 -31 710
|
|
17
|
+
-154 1008 -367 97 -70 278 -241 359 -340 481 -589 575 -1404 241 -2078 -271
|
|
18
|
+
-547 -759 -921 -1372 -1052 -118 -26 -142 -27 -381 -27 -240 0 -263 1 -383 27
|
|
19
|
+
-548 117 -987 422 -1282 892 -292 465 -365 1067 -194 1603 134 417 407 775
|
|
20
|
+
785 1027 255 171 594 288 906 314 149 12 172 12 313 1z"/>
|
|
21
|
+
<path d="M2425 4124 c-315 -48 -569 -134 -755 -254 -81 -53 -218 -185 -276
|
|
22
|
+
-266 -59 -82 -137 -248 -169 -359 -14 -49 -35 -146 -46 -215 -19 -116 -44
|
|
23
|
+
-243 -91 -450 -29 -127 -34 -314 -13 -441 46 -275 164 -501 369 -704 202 -200
|
|
24
|
+
419 -317 699 -376 121 -26 374 -32 472 -11 297 63 813 327 1112 569 172 139
|
|
25
|
+
289 280 367 444 60 124 86 227 93 371 16 317 -103 589 -448 1026 -68 86 -169
|
|
26
|
+
202 -224 258 -159 160 -381 297 -599 369 -170 57 -305 68 -491 39z"/>
|
|
27
|
+
</g>
|
|
28
|
+
</svg>
|
|
@@ -13,7 +13,12 @@
|
|
|
13
13
|
|
|
14
14
|
<link rel="stylesheet" href="/gscan.css?v=1">
|
|
15
15
|
|
|
16
|
-
<link rel="icon"
|
|
16
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
|
17
|
+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
|
18
|
+
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
|
19
|
+
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#0d1013">
|
|
20
|
+
<meta name="msapplication-TileColor" content="#0d1013">
|
|
21
|
+
<meta name="theme-color" content="#ffffff">
|
|
17
22
|
|
|
18
23
|
<meta name="HandheldFriendly" content="True">
|
|
19
24
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
package/lib/ast-linter/linter.js
CHANGED
|
@@ -6,17 +6,19 @@ class Linter {
|
|
|
6
6
|
/**
|
|
7
7
|
*
|
|
8
8
|
* @param {Object} [options]
|
|
9
|
-
* @param {string[]} options.partials - list of known theme partial names in ['mypartial', 'logo'] format
|
|
10
|
-
* @param {string[]} options.helpers - list of registered theme helper names in ['is', 'has'] format
|
|
11
|
-
* @param {
|
|
9
|
+
* @param {string[]?} options.partials - list of known theme partial names in ['mypartial', 'logo'] format
|
|
10
|
+
* @param {string[]?} options.helpers - list of registered theme helper names in ['is', 'has'] format
|
|
11
|
+
* @param {string[]?} options.inlinePartials - list of known local partial names in ['mypartial', 'logo'] format
|
|
12
|
+
* @param {Object?} options.customThemeSettings - list of registered custom theme settings in {'main_accent':{}} format
|
|
12
13
|
*/
|
|
13
|
-
constructor(options = {partials: [], helpers: [], customThemeSettings: {}}) {
|
|
14
|
+
constructor(options = {partials: [], helpers: [], inlinePartials: [], customThemeSettings: {}}) {
|
|
14
15
|
this.options = options;
|
|
15
16
|
// Ignore OS-specific path separator as Handlebars only uses forward-separators in its syntax
|
|
16
17
|
this.options.partials = this.options.partials.map(partial => normalizePath(partial));
|
|
17
18
|
|
|
18
19
|
this.partials = [];
|
|
19
20
|
this.helpers = [];
|
|
21
|
+
this.inlinePartials = [];
|
|
20
22
|
this.customThemeSettings = [];
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -40,6 +42,7 @@ class Linter {
|
|
|
40
42
|
source: config.source,
|
|
41
43
|
partials: this.options.partials,
|
|
42
44
|
helpers: this.options.helpers,
|
|
45
|
+
inlinePartials: this.options.inlinePartials,
|
|
43
46
|
customThemeSettings: this.options.customThemeSettings
|
|
44
47
|
});
|
|
45
48
|
|
|
@@ -53,6 +56,7 @@ class Linter {
|
|
|
53
56
|
this.context = {
|
|
54
57
|
partials: [],
|
|
55
58
|
helpers: [],
|
|
59
|
+
inlinePartials: [],
|
|
56
60
|
customThemeSettings: []
|
|
57
61
|
};
|
|
58
62
|
}
|
|
@@ -65,12 +69,12 @@ class Linter {
|
|
|
65
69
|
'PartialStatement',
|
|
66
70
|
'PartialBlockStatement',
|
|
67
71
|
'PathExpression',
|
|
68
|
-
'SubExpression'
|
|
72
|
+
'SubExpression',
|
|
73
|
+
'DecoratorBlock'
|
|
69
74
|
// the following types are not used in Ghost or we don't validate
|
|
70
75
|
// 'ContentStatement',
|
|
71
76
|
// 'CommentStatement,
|
|
72
77
|
// 'Decorator',
|
|
73
|
-
// 'DecoratorBlock'
|
|
74
78
|
];
|
|
75
79
|
|
|
76
80
|
nodeTypes.forEach((nodeType) => {
|
|
@@ -153,6 +157,10 @@ class Linter {
|
|
|
153
157
|
this.customThemeSettings = scanner.context.customThemeSettings;
|
|
154
158
|
}
|
|
155
159
|
|
|
160
|
+
if (scanner.context.inlinePartials) {
|
|
161
|
+
this.inlinePartials = scanner.context.inlinePartials;
|
|
162
|
+
}
|
|
163
|
+
|
|
156
164
|
return messages;
|
|
157
165
|
}
|
|
158
166
|
}
|
|
@@ -7,6 +7,7 @@ module.exports = class BaseRule {
|
|
|
7
7
|
this.source = options.source;
|
|
8
8
|
this.partials = options.partials;
|
|
9
9
|
this.helpers = options.helpers;
|
|
10
|
+
this.inlinePartials = options.inlinePartials || [];
|
|
10
11
|
this.customThemeSettings = options.customThemeSettings;
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -27,7 +28,8 @@ module.exports = class BaseRule {
|
|
|
27
28
|
'PartialStatement',
|
|
28
29
|
'PartialBlockStatement',
|
|
29
30
|
'PathExpression',
|
|
30
|
-
'SubExpression'
|
|
31
|
+
'SubExpression',
|
|
32
|
+
'DecoratorBlock'
|
|
31
33
|
];
|
|
32
34
|
|
|
33
35
|
// this object keeps an array of functions for each node type, eventually
|
|
@@ -111,8 +113,44 @@ module.exports = class BaseRule {
|
|
|
111
113
|
this._log(reportedResult);
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
isValidPartialReference(node) {
|
|
115
|
-
return node.name.original === '@partial-block'
|
|
116
|
+
isValidPartialReference(node, parents) {
|
|
117
|
+
return node.name.original === '@partial-block'
|
|
118
|
+
|| this.partials.includes(node.name.original)
|
|
119
|
+
|| this.isAccessibleInlinePartial(node, parents);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Make sure one inline partial match the partial usage
|
|
123
|
+
isAccessibleInlinePartial(node, parents) {
|
|
124
|
+
const parentNodes = parents || [];
|
|
125
|
+
return this.inlinePartials.some((partial) => {
|
|
126
|
+
if (partial.node !== node.name.original) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
//filter candidates so that the inline partial is in the same scope as where it's used
|
|
131
|
+
for (let i = 0; i < partial.parents.length; i++) {
|
|
132
|
+
const declarationParent = partial.parents[i];
|
|
133
|
+
for (let j = 0; j < parentNodes.length; j++) {
|
|
134
|
+
const usageParent = parentNodes[j];
|
|
135
|
+
|
|
136
|
+
// If we found a common ancestor, we're good
|
|
137
|
+
// To compare two nodes, we check the type of the node and the location of the code
|
|
138
|
+
if (usageParent.type === declarationParent.type &&
|
|
139
|
+
usageParent.loc.source === declarationParent.loc.source &&
|
|
140
|
+
usageParent.loc.start.line === declarationParent.loc.start.line &&
|
|
141
|
+
usageParent.loc.start.column === declarationParent.loc.start.column &&
|
|
142
|
+
usageParent.loc.end.line === declarationParent.loc.end.line &&
|
|
143
|
+
usageParent.loc.end.column === declarationParent.loc.end.column) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// If we found a block before finding a common ancestor, the usage can't access the declaration
|
|
148
|
+
if (['BlockStatement','PartialBlockStatement','DecoratorBlock'].includes(declarationParent.type)) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
116
154
|
}
|
|
117
155
|
|
|
118
156
|
isValidHelperReference(nodeName) {
|
|
@@ -2,14 +2,32 @@ const Rule = require('./base');
|
|
|
2
2
|
const {getPartialName} = require('../helpers');
|
|
3
3
|
|
|
4
4
|
module.exports = class NoUnknownPartials extends Rule {
|
|
5
|
-
_checkForUnknownPartials(node) {
|
|
5
|
+
_checkForUnknownPartials(node, visitor) {
|
|
6
6
|
if (node.name) {
|
|
7
|
-
if (!this.isValidPartialReference(node)) {
|
|
8
|
-
|
|
9
|
-
message: `The partial ${getPartialName(node)} could not be found`,
|
|
7
|
+
if (!this.isValidPartialReference(node, visitor.parents)) {
|
|
8
|
+
const logObject = {
|
|
10
9
|
line: node.loc && node.loc.start.line,
|
|
11
10
|
column: node.loc && node.loc.start.column,
|
|
12
11
|
source: this.sourceForNode(node)
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Dynamic partials (https://handlebarsjs.com/guide/partials.html#dynamic-partials)
|
|
15
|
+
if (node.name.type === 'SubExpression') {
|
|
16
|
+
if (node.type === 'PartialBlockStatement') {
|
|
17
|
+
// A dynamic partial is valid when declared as a block
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (node.type === 'PartialStatement') {
|
|
21
|
+
return this.log({
|
|
22
|
+
message: `Inlined dynamic partials like <code>{{> (dynamicPartial) }}</code> can result in page errors if the partial does not exist, use block dynamic partials instead.`,
|
|
23
|
+
...logObject
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.log({
|
|
29
|
+
message: `The partial ${getPartialName(node)} could not be found`,
|
|
30
|
+
...logObject
|
|
13
31
|
});
|
|
14
32
|
}
|
|
15
33
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const Rule = require('./base');
|
|
2
|
+
const get = require('lodash/get');
|
|
3
|
+
|
|
4
|
+
module.exports = class MarkDeclaredInlinePartials extends Rule {
|
|
5
|
+
_markDeclaredInlinePartials(node, visitor) {
|
|
6
|
+
if (get(node, 'path.original') === 'inline' && get(node, 'params.length') > 0) {
|
|
7
|
+
const nodeName = get(node, 'params[0].original');
|
|
8
|
+
this.scanner.context.inlinePartials.push({
|
|
9
|
+
node: nodeName,
|
|
10
|
+
parents: visitor.parents.map(p => ({
|
|
11
|
+
type: p.type,
|
|
12
|
+
loc: p.loc
|
|
13
|
+
})),
|
|
14
|
+
type: node.type,
|
|
15
|
+
loc: node.loc,
|
|
16
|
+
parameters: node.params ? node.params.map(p => p.original) : null
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
visitor() {
|
|
22
|
+
return {
|
|
23
|
+
DecoratorBlock: this._markDeclaredInlinePartials.bind(this)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -14,6 +14,22 @@ function processFileFunction(files, failures, theme, partialsFound) {
|
|
|
14
14
|
|
|
15
15
|
processedFiles.push(themeFile.file);
|
|
16
16
|
|
|
17
|
+
// Reset inline partial variables
|
|
18
|
+
linter.inlinePartials = [];
|
|
19
|
+
linter.options.inlinePartials = [];
|
|
20
|
+
|
|
21
|
+
linter.verify({
|
|
22
|
+
parsed: themeFile.parsed,
|
|
23
|
+
rules: [
|
|
24
|
+
require('../ast-linter/rules/mark-declared-inline-partials')
|
|
25
|
+
],
|
|
26
|
+
source: themeFile.content,
|
|
27
|
+
moduleId: themeFile.file
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Store the inline partials for the actual partial linting
|
|
31
|
+
linter.options.inlinePartials = linter.inlinePartials;
|
|
32
|
+
|
|
17
33
|
const astResults = linter.verify({
|
|
18
34
|
parsed: themeFile.parsed,
|
|
19
35
|
rules: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gscan",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.21.0",
|
|
4
4
|
"description": "Scans Ghost themes looking for errors, deprecations, features and compatibility",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ghost",
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@sentry/node": "6.16.1",
|
|
44
|
-
"@tryghost/config": "0.2.
|
|
45
|
-
"@tryghost/debug": "0.1.
|
|
44
|
+
"@tryghost/config": "0.2.2",
|
|
45
|
+
"@tryghost/debug": "0.1.10",
|
|
46
46
|
"@tryghost/ignition-errors": "0.1.8",
|
|
47
|
-
"@tryghost/logging": "2.0.
|
|
47
|
+
"@tryghost/logging": "2.0.1",
|
|
48
48
|
"@tryghost/pretty-cli": "1.2.22",
|
|
49
|
-
"@tryghost/server": "0.1.
|
|
49
|
+
"@tryghost/server": "0.1.4",
|
|
50
50
|
"@tryghost/zip": "1.1.18",
|
|
51
51
|
"bluebird": "3.7.2",
|
|
52
52
|
"chalk": "4.1.2",
|
package/app/public/favicon.png
DELETED
|
Binary file
|