-
Notifications
You must be signed in to change notification settings - Fork 7
/
index.js
166 lines (149 loc) · 5.16 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
'use strict';
const path = require('path');
const fs = require('fs');
const normalizeUrl = require('normalize-url');
const Ajv = require('ajv');
const got = require('got');
const betterAjvErrors = require('better-ajv-errors');
const create = require('./lib/cli/create');
let ajv;
let compiledSchema;
let ajvElement;
let compiledSchemaElement;
const schema = module.exports.schema = require('./schema.json');
const supportElementSchema = module.exports.schema = require('./support-element-schema.json');
module.exports.defaultPackageSupport = 'package-support.json';
module.exports.create = create;
function getBetterAjvErrorsOptions (cli) {
const options = { format: 'js' };
if (cli === true) {
options.format = 'cli';
}
return options;
}
module.exports.validateSupportElement = (obj, cli = false) => {
if (!ajvElement) {
ajvElement = new Ajv({ jsonPointers: true });
compiledSchemaElement = ajvElement.compile(supportElementSchema);
}
const validates = compiledSchemaElement(obj);
if (!validates) {
const err = new Error('Validation Failed');
err.validationErrors = compiledSchemaElement.errors;
err.prettyValidationErrors = betterAjvErrors(supportElementSchema, obj, compiledSchemaElement.errors, getBetterAjvErrorsOptions(cli));
err.validationSchema = compiledSchemaElement.schema;
throw err;
}
return true;
};
module.exports.validate = (obj, cli = false) => {
if (!ajv) {
ajv = new Ajv({ jsonPointers: true });
compiledSchema = ajv.compile(schema);
}
const validates = compiledSchema(obj);
if (!validates) {
const err = new Error('Validation Failed');
err.validationErrors = compiledSchema.errors;
err.prettyValidationErrors = betterAjvErrors(schema, obj, compiledSchema.errors, getBetterAjvErrorsOptions(cli));
err.validationSchema = compiledSchema.schema;
throw err;
}
return true;
};
// extract the URL for the support info from the pkg info
module.exports.getRemoteSupportInfoUrl = (repository, supportPath) => {
const gitHubInitialPath = '/blob/HEAD/';
if (repository && (repository.type === 'git')) {
const directory = repository.directory || '';
let remoteURL = repository.url;
const trailerLocation = remoteURL.indexOf('.git');
if (trailerLocation >= 0) {
remoteURL = remoteURL.substring(0, trailerLocation) +
gitHubInitialPath + '/' + directory +
'/' + supportPath;
}
return normalizeUrl(remoteURL);
} else {
return 'unknown';
}
};
// the path should not try to escape the root as it
// is specified to be a relative path
module.exports.sanitizePath = (basePath, inputPath, basePathOverride) => {
const effectiveBasePath = path.normalize(basePathOverride || basePath);
const candidatePath = path.join(basePath, inputPath);
let ret = path.basename(inputPath);
if (candidatePath.indexOf(effectiveBasePath) === 0) {
// inputPath did not try to escape
ret = inputPath;
}
return ret;
};
async function resolveSupportInfo (supportInfo, fetchCanonical) {
supportInfo.resolved = false;
if (fetchCanonical) {
const url = normalizeUrl(supportInfo.url
.replace('blob', '')
.replace('github.com', 'raw.githubusercontent.com'));
try {
const result = await got(url);
supportInfo.contents = result.body;
supportInfo.resolved = true;
} catch (e) {
supportInfo.error = e;
}
}
}
module.exports.getSupportData = async (pkg, pkgPath, preferCanonical, basePathOverride, fetchCanonical) => {
const supportInfo = { contents: 'unknown', url: '', resolved: true };
if (pkg.support) {
if ((pkg.support === true) || (typeof pkg.support === 'string')) {
const supportInfoName = (pkg.support === true)
? module.exports.defaultPackageSupport : module.exports.sanitizePath(pkgPath, pkg.support, basePathOverride);
const localPath = path.join(pkgPath, supportInfoName);
if (!preferCanonical && fs.existsSync(localPath)) {
supportInfo.contents = fs.readFileSync(localPath);
supportInfo.resolved = true;
} else {
supportInfo.url = module.exports.getRemoteSupportInfoUrl(pkg.repository, supportInfoName);
await resolveSupportInfo(supportInfo, fetchCanonical);
}
} else if (typeof pkg.support === 'object') {
const supportInfoName = pkg.support.path ? pkg.support.path : module.exports.defaultPackageSupport;
supportInfo.url = module.exports.getRemoteSupportInfoUrl(pkg.support.repository, supportInfoName);
await resolveSupportInfo(supportInfo, fetchCanonical);
}
}
return supportInfo;
};
/**
* Returns list of target Node.js versions for package-support.json file
*/
module.exports.getNodeJsTargetVersionsList = () => {
return [
'abandoned',
'none',
'all',
'lts',
'active',
'lts_active',
'lts_latest',
'supported',
'current'
];
};
/**
* Returns list of response types for package-support.json file
*/
module.exports.getSupportResponseTypesList = () => {
const schemaOptions = [
'none',
'time-permitting',
'24-7'
];
for (let daysForResponse = 1; daysForResponse <= 7; daysForResponse++) {
schemaOptions.push(`regular-${daysForResponse}`);
}
return schemaOptions;
};