gscan 4.9.4 → 4.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/ghost-version.js +2 -2
- package/app/index.js +5 -4
- package/app/middlewares/log-request.js +1 -1
- package/app/middlewares/upload-validation.js +1 -1
- package/lib/checker.js +55 -8
- package/lib/checks/010-package-json.js +0 -1
- package/lib/checks/080-helper-usage.js +3 -8
- package/lib/checks/090-template-syntax.js +4 -7
- package/lib/index.js +1 -55
- package/lib/read-zip.js +2 -2
- package/lib/specs/index.js +1 -1
- package/lib/utils/index.js +2 -1
- package/lib/utils/package-json.js +20 -0
- package/package.json +11 -7
- package/app/logging.js +0 -12
package/app/ghost-version.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const debug = require('
|
|
1
|
+
const debug = require('@tryghost/debug')('ghost-version');
|
|
2
2
|
const exec = require('child_process').exec;
|
|
3
|
-
const config = require('
|
|
3
|
+
const config = require('@tryghost/config');
|
|
4
4
|
|
|
5
5
|
let ttl;
|
|
6
6
|
let ghostVersion;
|
package/app/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
|
-
const debug = require('
|
|
2
|
+
const debug = require('@tryghost/debug')('app');
|
|
3
3
|
const hbs = require('express-hbs');
|
|
4
4
|
const multer = require('multer');
|
|
5
|
-
const server = require('
|
|
6
|
-
const
|
|
5
|
+
const server = require('@tryghost/server');
|
|
6
|
+
const config = require('@tryghost/config');
|
|
7
|
+
const errors = require('@tryghost/ignition-errors');
|
|
7
8
|
const gscan = require('../lib');
|
|
8
9
|
const fs = require('fs-extra');
|
|
9
10
|
const logRequest = require('./middlewares/log-request');
|
|
@@ -109,4 +110,4 @@ app.use(function (err, req, res, next) {
|
|
|
109
110
|
res.render(template, {message: err.message, stack: err.stack, details: err.errorDetails, context: err.context});
|
|
110
111
|
});
|
|
111
112
|
|
|
112
|
-
server.start(app);
|
|
113
|
+
server.start(app, config.get('port'));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// NOTE: this middleware was extracted from Ghost core validation for theme uploads
|
|
2
2
|
// might be useful to unify this logic in the future if it's extracted to separate module
|
|
3
3
|
const path = require('path');
|
|
4
|
-
const errors = require('
|
|
4
|
+
const errors = require('@tryghost/ignition-errors');
|
|
5
5
|
|
|
6
6
|
const checkFileExists = function checkFileExists(fileData) {
|
|
7
7
|
return !!(fileData.mimetype && fileData.path);
|
package/lib/checker.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
const Promise = require('bluebird');
|
|
2
2
|
const _ = require('lodash');
|
|
3
3
|
const requireDir = require('require-dir');
|
|
4
|
-
const
|
|
5
|
-
const readTheme = require('./read-theme');
|
|
4
|
+
const errors = require('@tryghost/ignition-errors');
|
|
6
5
|
const versions = require('./utils').versions;
|
|
7
6
|
|
|
8
|
-
const checks = requireDir('./checks');
|
|
9
|
-
|
|
10
7
|
// An object containing helpers as keys and their labs flag as values
|
|
11
8
|
// E.g. match: 'matchHelper'
|
|
12
9
|
const labsEnabledHelpers = {
|
|
@@ -24,7 +21,9 @@ const labsEnabledHelpers = {
|
|
|
24
21
|
* @param {Object=} [options.labs] object containing boolean flags for enabled labs features
|
|
25
22
|
* @returns {Promise<Object>}
|
|
26
23
|
*/
|
|
27
|
-
const
|
|
24
|
+
const check = function checkAll(themePath, options = {}) {
|
|
25
|
+
// Require checks late to avoid loading all until used
|
|
26
|
+
const checks = requireDir('./checks');
|
|
28
27
|
const passedVersion = _.get(options, 'checkVersion', versions.default);
|
|
29
28
|
let version = passedVersion;
|
|
30
29
|
|
|
@@ -41,13 +40,15 @@ const checker = function checkAll(themePath, options = {}) {
|
|
|
41
40
|
}
|
|
42
41
|
});
|
|
43
42
|
|
|
43
|
+
// Require readTheme late to avoid loading entire AST parser until used
|
|
44
|
+
const readTheme = require('./read-theme');
|
|
44
45
|
return readTheme(themePath)
|
|
45
46
|
.then(function (theme) {
|
|
46
47
|
// set the major version to check
|
|
47
48
|
theme.checkedVersion = versions[version].major;
|
|
48
49
|
|
|
49
|
-
return Promise.reduce(_.values(checks), function (themeToCheck,
|
|
50
|
-
return
|
|
50
|
+
return Promise.reduce(_.values(checks), function (themeToCheck, checkFunction) {
|
|
51
|
+
return checkFunction(themeToCheck, options, themePath);
|
|
51
52
|
}, theme);
|
|
52
53
|
})
|
|
53
54
|
.catch((error) => {
|
|
@@ -61,4 +62,50 @@ const checker = function checkAll(themePath, options = {}) {
|
|
|
61
62
|
});
|
|
62
63
|
};
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
const checkZip = async function checkZip(path, options) {
|
|
66
|
+
options = Object.assign({}, {
|
|
67
|
+
keepExtractedDir: false
|
|
68
|
+
}, options);
|
|
69
|
+
|
|
70
|
+
let zip;
|
|
71
|
+
|
|
72
|
+
if (_.isString(path)) {
|
|
73
|
+
zip = {
|
|
74
|
+
path,
|
|
75
|
+
name: path.match(/(.*\/)?(.*).zip$/)[2]
|
|
76
|
+
};
|
|
77
|
+
} else {
|
|
78
|
+
zip = _.clone(path);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const readZip = require('./read-zip');
|
|
83
|
+
const {path: extractedZipPath} = await readZip(zip);
|
|
84
|
+
const theme = await check(extractedZipPath, Object.assign({themeName: zip.name}, options));
|
|
85
|
+
|
|
86
|
+
if (options.keepExtractedDir) {
|
|
87
|
+
return theme;
|
|
88
|
+
} else {
|
|
89
|
+
const fs = require('fs-extra');
|
|
90
|
+
await fs.remove(zip.origPath);
|
|
91
|
+
return theme;
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if (!errors.utils.isIgnitionError(error)) {
|
|
95
|
+
throw new errors.ValidationError({
|
|
96
|
+
message: 'Failed to check zip file',
|
|
97
|
+
help: 'Your zip file might be corrupted, try unzipping and zipping again.',
|
|
98
|
+
errorDetails: error.message,
|
|
99
|
+
context: zip.name,
|
|
100
|
+
err: error
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
module.exports = {
|
|
109
|
+
check,
|
|
110
|
+
checkZip
|
|
111
|
+
};
|
|
@@ -4,7 +4,6 @@ const isEmail = require('validator/lib/isEmail');
|
|
|
4
4
|
const _private = {};
|
|
5
5
|
const packageJSONFileName = 'package.json';
|
|
6
6
|
const versions = require('../utils').versions;
|
|
7
|
-
// const debug = require('ghost-ignition').debug('checks:package-json');
|
|
8
7
|
|
|
9
8
|
const isSnakeCase = (str) => {
|
|
10
9
|
return /^[a-z0-9]+[a-z0-9_]*$/.test(str);
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
2
|
const spec = require('../specs');
|
|
3
|
-
const versions = require('../utils')
|
|
4
|
-
const packageJSONFileName = 'package.json';
|
|
3
|
+
const {versions, getPackageJSON} = require('../utils');
|
|
5
4
|
|
|
6
5
|
module.exports = function checkUsage(theme, options) {
|
|
7
6
|
const checkVersion = _.get(options, 'checkVersion', versions.default);
|
|
8
7
|
let ruleSet = spec.get([checkVersion]);
|
|
9
|
-
|
|
10
|
-
let targetApiVersion = versions.default;
|
|
11
|
-
if (packageJSON && packageJSON.content) {
|
|
12
|
-
let packageJSONParsed = JSON.parse(packageJSON.content);
|
|
13
|
-
targetApiVersion = (packageJSONParsed && packageJSONParsed.engines && packageJSONParsed.engines['ghost-api']) || versions.default;
|
|
14
|
-
}
|
|
8
|
+
const packageJSON = getPackageJSON(theme);
|
|
9
|
+
let targetApiVersion = (packageJSON && packageJSON.engines && packageJSON.engines['ghost-api']) || versions.default;
|
|
15
10
|
|
|
16
11
|
// CASE: 080-helper-usage checks only needs `rules` that start with `GS080-`
|
|
17
12
|
const ruleRegex = /GS080-.*/g;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
2
|
const spec = require('../specs');
|
|
3
|
-
const {versions, normalizePath} = require('../utils');
|
|
3
|
+
const {versions, normalizePath, getPackageJSON} = require('../utils');
|
|
4
4
|
const ASTLinter = require('../ast-linter');
|
|
5
5
|
|
|
6
6
|
function processFileFunction(files, failures, rules) {
|
|
@@ -40,13 +40,10 @@ function processFileFunction(files, failures, rules) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
function getCustomThemeSettings(theme) {
|
|
43
|
-
|
|
43
|
+
const packageJSON = getPackageJSON(theme);
|
|
44
44
|
let customThemeSettingsConfig;
|
|
45
|
-
if (packageJSON && packageJSON.
|
|
46
|
-
|
|
47
|
-
if (packageJSONParsed.config && packageJSONParsed.config.custom) {
|
|
48
|
-
customThemeSettingsConfig = packageJSONParsed.config.custom;
|
|
49
|
-
}
|
|
45
|
+
if (packageJSON && packageJSON.config && packageJSON.config.custom) {
|
|
46
|
+
customThemeSettingsConfig = packageJSON.config.custom;
|
|
50
47
|
}
|
|
51
48
|
return customThemeSettingsConfig;
|
|
52
49
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,59 +1,5 @@
|
|
|
1
|
-
const
|
|
2
|
-
const fs = require('fs-extra');
|
|
3
|
-
const check = require('./checker');
|
|
1
|
+
const {check, checkZip} = require('./checker');
|
|
4
2
|
const format = require('./format');
|
|
5
|
-
const readZip = require('./read-zip');
|
|
6
|
-
const {errors} = require('ghost-ignition');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
* @param {string} path zip file path or a folder path containing a theme
|
|
11
|
-
* @param {Object} options
|
|
12
|
-
* @param {boolean} options.keepExtractedDir flag controling if the directory with extracted zip should stay after the check is complete
|
|
13
|
-
* @param {string} options.checkVersion version to check the theme against
|
|
14
|
-
* @param {Object=} [options.labs] object containing boolean flags for enabled labs features
|
|
15
|
-
* @returns {Promise<any>}
|
|
16
|
-
*/
|
|
17
|
-
const checkZip = async function checkZip(path, options) {
|
|
18
|
-
options = Object.assign({}, {
|
|
19
|
-
keepExtractedDir: false
|
|
20
|
-
}, options);
|
|
21
|
-
|
|
22
|
-
let zip;
|
|
23
|
-
|
|
24
|
-
if (_.isString(path)) {
|
|
25
|
-
zip = {
|
|
26
|
-
path,
|
|
27
|
-
name: path.match(/(.*\/)?(.*).zip$/)[2]
|
|
28
|
-
};
|
|
29
|
-
} else {
|
|
30
|
-
zip = _.clone(path);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
const {path: extractedZipPath} = await readZip(zip);
|
|
35
|
-
const theme = await check(extractedZipPath, Object.assign({themeName: zip.name}, options));
|
|
36
|
-
|
|
37
|
-
if (options.keepExtractedDir) {
|
|
38
|
-
return theme;
|
|
39
|
-
} else {
|
|
40
|
-
await fs.remove(zip.origPath);
|
|
41
|
-
return theme;
|
|
42
|
-
}
|
|
43
|
-
} catch (error) {
|
|
44
|
-
if (!errors.utils.isIgnitionError(error)) {
|
|
45
|
-
throw new errors.ValidationError({
|
|
46
|
-
message: 'Failed to check zip file',
|
|
47
|
-
help: 'Your zip file might be corrupted, try unzipping and zipping again.',
|
|
48
|
-
errorDetails: error.message,
|
|
49
|
-
context: zip.name,
|
|
50
|
-
err: error
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
throw error;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
3
|
|
|
58
4
|
module.exports = {
|
|
59
5
|
check,
|
package/lib/read-zip.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const debug = require('
|
|
1
|
+
const debug = require('@tryghost/debug')('zip');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const Promise = require('bluebird');
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const glob = require('glob');
|
|
6
6
|
const {extract} = require('@tryghost/zip');
|
|
7
|
-
const
|
|
7
|
+
const errors = require('@tryghost/ignition-errors');
|
|
8
8
|
const uuid = require('uuid');
|
|
9
9
|
const _ = require('lodash');
|
|
10
10
|
|
package/lib/specs/index.js
CHANGED
package/lib/utils/index.js
CHANGED
|
@@ -16,5 +16,6 @@ module.exports = {
|
|
|
16
16
|
// `docs` is used to generate the URLs that link to documentation and needs to be updated whenever
|
|
17
17
|
// we release a new version on ghost.org/docs/api/
|
|
18
18
|
versions: require('./versions.json'),
|
|
19
|
-
normalizePath
|
|
19
|
+
normalizePath,
|
|
20
|
+
getPackageJSON: require('./package-json')
|
|
20
21
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the package.json JSON content. Note that this function never throws,
|
|
3
|
+
* even when there is a JSON parsing error.
|
|
4
|
+
* @param {Object} theme The theme to extract package.json from.
|
|
5
|
+
* @returns {Object} The content of the package.json file, or `null` if
|
|
6
|
+
* something happened (no file, JSON parsing error...).
|
|
7
|
+
*/
|
|
8
|
+
function getJSON(theme) {
|
|
9
|
+
let packageJSON = theme.files.find(item => item.file === 'package.json');
|
|
10
|
+
if (packageJSON && packageJSON.content) {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(packageJSON.content);
|
|
13
|
+
} catch (e) {
|
|
14
|
+
// Do nothing here
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = getJSON;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gscan",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.10.3",
|
|
4
4
|
"description": "Scans Ghost themes looking for errors, deprecations, features and compatibility",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ghost",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"url": "git@github.com:TryGhost/gscan.git"
|
|
15
15
|
},
|
|
16
16
|
"engines": {
|
|
17
|
-
"node": "^12.
|
|
17
|
+
"node": "^12.22.1 || ^14.17.0 || ^16.13.0"
|
|
18
18
|
},
|
|
19
19
|
"bugs": {
|
|
20
20
|
"url": "https://github.com/TryGhost/gscan/issues"
|
|
@@ -40,16 +40,20 @@
|
|
|
40
40
|
"gscan": "./bin/cli.js"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@sentry/node": "6.
|
|
43
|
+
"@sentry/node": "6.15.0",
|
|
44
|
+
"@tryghost/config": "0.2.1",
|
|
45
|
+
"@tryghost/debug": "0.1.9",
|
|
46
|
+
"@tryghost/ignition-errors": "0.1.8",
|
|
47
|
+
"@tryghost/logging": "1.0.0",
|
|
44
48
|
"@tryghost/pretty-cli": "1.2.22",
|
|
49
|
+
"@tryghost/server": "0.1.0",
|
|
45
50
|
"@tryghost/zip": "1.1.18",
|
|
46
51
|
"bluebird": "3.7.2",
|
|
47
52
|
"chalk": "4.1.2",
|
|
48
|
-
"common-tags": "1.8.
|
|
53
|
+
"common-tags": "1.8.2",
|
|
49
54
|
"express": "4.17.1",
|
|
50
55
|
"express-hbs": "2.4.0",
|
|
51
56
|
"fs-extra": "9.1.0",
|
|
52
|
-
"ghost-ignition": "4.6.3",
|
|
53
57
|
"glob": "7.2.0",
|
|
54
58
|
"lodash": "4.17.21",
|
|
55
59
|
"multer": "1.4.3",
|
|
@@ -60,14 +64,14 @@
|
|
|
60
64
|
"validator": "13.0.0"
|
|
61
65
|
},
|
|
62
66
|
"devDependencies": {
|
|
63
|
-
"eslint": "
|
|
67
|
+
"eslint": "8.1.0",
|
|
64
68
|
"eslint-plugin-ghost": "2.1.0",
|
|
65
69
|
"istanbul": "0.4.5",
|
|
66
70
|
"mocha": "9.0.2",
|
|
67
71
|
"nodemon": "2.0.7",
|
|
68
72
|
"rewire": "5.0.0",
|
|
69
73
|
"should": "13.2.3",
|
|
70
|
-
"sinon": "
|
|
74
|
+
"sinon": "12.0.0"
|
|
71
75
|
},
|
|
72
76
|
"files": [
|
|
73
77
|
"lib",
|
package/app/logging.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
var config = require('ghost-ignition').config();
|
|
2
|
-
|
|
3
|
-
// see defaults in GhostLogger
|
|
4
|
-
var logging = require('ghost-ignition').logging({
|
|
5
|
-
path: config.get('logging:path'),
|
|
6
|
-
domain: config.get('logging:domain'),
|
|
7
|
-
mode: config.get('logging:mode'),
|
|
8
|
-
level: config.get('logging:level'),
|
|
9
|
-
transports: config.get('logging:transports')
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
module.exports = logging;
|