amphtml-validator
Advanced tools
Comparing version 1.0.23 to 1.0.24
@@ -22,10 +22,10 @@ #!/usr/bin/env node | ||
global.assert = require('assert'); | ||
var fs = require('fs'); | ||
const fs = require('fs'); | ||
global.path = require('path'); | ||
var execFile = require('child_process').execFile; | ||
var JasmineRunner = require('jasmine'); | ||
var jasmine = new JasmineRunner(); | ||
const JasmineRunner = require('jasmine'); | ||
const {execFile} = require('child_process'); | ||
const jasmine = new JasmineRunner(); | ||
var ampValidator = require('./index.js'); | ||
const ampValidator = require('./index.js'); | ||
@@ -38,3 +38,4 @@ it('deployed validator rejects the empty file', function(done) { | ||
.then(function(instance) { | ||
var validationResult = instance.validateString(''); | ||
const validationResult = instance.validateString(''); | ||
expect(validationResult.status).toBe('FAIL'); | ||
@@ -57,3 +58,4 @@ done(); | ||
.then(function(instance) { | ||
var validationResult = instance.validateString(''); | ||
const validationResult = instance.validateString(''); | ||
expect(validationResult.status).toBe('FAIL'); | ||
@@ -70,7 +72,8 @@ done(); | ||
// Note: This will use the validator that was built with build.py. | ||
var mini = fs.readFileSync( | ||
const mini = fs.readFileSync( | ||
'../testdata/feature_tests/minimum_valid_amp.html', 'utf-8').trim(); | ||
ampValidator.getInstance(/*validatorJs*/ '../dist/validator_minified.js') | ||
.then(function(instance) { | ||
var validationResult = instance.validateString(mini); | ||
const validationResult = instance.validateString(mini); | ||
expect(validationResult.status).toBe('PASS'); | ||
@@ -87,3 +90,3 @@ done(); | ||
// Note: This will use the validator that was built with build.py. | ||
var mini = fs.readFileSync( | ||
const mini = fs.readFileSync( | ||
'../testdata/amp4ads_feature_tests/min_valid_amp4ads.html', 'utf-8') | ||
@@ -93,3 +96,4 @@ .trim(); | ||
.then(function(instance) { | ||
var validationResult = instance.validateString(mini, 'AMP4ADS'); | ||
const validationResult = instance.validateString(mini, 'AMP4ADS'); | ||
expect(validationResult.status).toBe('PASS'); | ||
@@ -116,6 +120,6 @@ done(); | ||
// Note: This will use the validator that was built with build.py. | ||
var severalErrorsHtml = | ||
const severalErrorsHtml = | ||
fs.readFileSync('../testdata/feature_tests/several_errors.html', 'utf-8') | ||
.trim(); | ||
var severalErrorsOut = | ||
const severalErrorsOut = | ||
fs.readFileSync('../testdata/feature_tests/several_errors.out', 'utf-8') | ||
@@ -128,9 +132,10 @@ .split('\n') | ||
.then(function(instance) { | ||
var validationResult = instance.validateString(severalErrorsHtml); | ||
const validationResult = instance.validateString(severalErrorsHtml); | ||
expect(validationResult.status).toBe('FAIL'); | ||
// Here, we assemble the output from the validationResult that was | ||
// computed by the validator and compare it with the golden file. | ||
var out = 'FAIL\n'; | ||
for (var ii = 0; ii < validationResult.errors.length; ii++) { | ||
var error = validationResult.errors[ii]; | ||
let out = 'FAIL\n'; | ||
for (let ii = 0; ii < validationResult.errors.length; ii++) { | ||
const error = validationResult.errors[ii]; | ||
out += 'feature_tests/several_errors.html'; | ||
@@ -143,2 +148,3 @@ out += ':' + error.line + ':' + error.col + ' ' + error.message; | ||
} | ||
expect(out).toBe(severalErrorsOut); | ||
@@ -169,15 +175,17 @@ done(); | ||
it('also works with newInstance', function() { | ||
var mini = fs.readFileSync( | ||
const mini = fs.readFileSync( | ||
'../testdata/feature_tests/minimum_valid_amp.html', 'utf-8').trim(); | ||
var validatorJsContents = | ||
const validatorJsContents = | ||
fs.readFileSync('../dist/validator_minified.js', 'utf-8'); | ||
var resultForMini = | ||
const resultForMini = | ||
ampValidator.newInstance(validatorJsContents).validateString(mini); | ||
expect(resultForMini.status).toBe('PASS'); | ||
var severalErrorsHtml = | ||
const severalErrorsHtml = | ||
fs.readFileSync('../testdata/feature_tests/several_errors.html', 'utf-8') | ||
.trim(); | ||
var resultForSeveralErrors = ampValidator.newInstance(validatorJsContents) | ||
.validateString(severalErrorsHtml); | ||
const resultForSeveralErrors = ampValidator.newInstance(validatorJsContents) | ||
.validateString(severalErrorsHtml); | ||
expect(resultForSeveralErrors.status).toBe('FAIL'); | ||
@@ -187,9 +195,9 @@ }); | ||
it('emits text if --format=text is specified on command line', function(done) { | ||
var severalErrorsOut = | ||
const severalErrorsOut = | ||
fs.readFileSync('../testdata/feature_tests/several_errors.out', 'utf-8') | ||
.split('\n') | ||
.filter(isErrorLine) | ||
.splice(1) // trim 1st line | ||
.splice(1) // trim 1st line | ||
.join('\n') | ||
.replace(/ \[[A-Z_]+\]/g, ''); // trim error categories | ||
.replace(/ \[[A-Z_]+\]/g, ''); // trim error categories | ||
execFile( | ||
@@ -201,7 +209,7 @@ process.execPath, | ||
'feature_tests/several_errors.html', | ||
'feature_tests/minimum_valid_amp.html' | ||
'feature_tests/minimum_valid_amp.html', | ||
], | ||
{'cwd': '../testdata'}, // Run inside the testdata dir to match paths. | ||
function (error, stdout, stderr) { | ||
expect(error).toBeDefined(); // At least one file had errors. | ||
{'cwd': '../testdata'}, // Run inside the testdata dir to match paths. | ||
function(error, stdout, stderr) { | ||
expect(error).toBeDefined(); // At least one file had errors. | ||
expect(stderr).toBe(severalErrorsOut); | ||
@@ -220,8 +228,8 @@ expect(stdout).toBe('feature_tests/minimum_valid_amp.html: PASS\n'); | ||
'feature_tests/several_errors.html', | ||
'feature_tests/minimum_valid_amp.html' | ||
'feature_tests/minimum_valid_amp.html', | ||
], | ||
{'cwd': '../testdata'}, // Run inside the testdata dir to match paths. | ||
function (error, stdout, stderr) { | ||
expect(error).toBeDefined(); // At least one file had errors | ||
expect(stderr).toBe(''); // entire json results will be on stdout | ||
{'cwd': '../testdata'}, // Run inside the testdata dir to match paths. | ||
function(error, stdout, stderr) { | ||
expect(error).toBeDefined(); // At least one file had errors | ||
expect(stderr).toBe(''); // entire json results will be on stdout | ||
@@ -231,8 +239,11 @@ // We inspect the parsed JSON but not very deep, to keep this test | ||
// changes its outputs slightly. | ||
var parsedJson = JSON.parse(stdout); | ||
const parsedJson = JSON.parse(stdout); | ||
expect(parsedJson['feature_tests/minimum_valid_amp.html']) | ||
.toBeDefined(); | ||
expect(parsedJson['feature_tests/several_errors.html']).toBeDefined(); | ||
expect(parsedJson['feature_tests/minimum_valid_amp.html'].status) | ||
.toBe('PASS'); | ||
expect(parsedJson['feature_tests/several_errors.html'].status) | ||
@@ -245,11 +256,11 @@ .toBe('FAIL'); | ||
it('supports AMP4ADS with --html_format command line option', function(done) { | ||
var severalErrorsOut = | ||
const severalErrorsOut = | ||
fs.readFileSync( | ||
'../testdata/amp4ads_feature_tests/style-amp-custom.out', | ||
'utf-8') | ||
'../testdata/amp4ads_feature_tests/style-amp-custom.out', | ||
'utf-8') | ||
.split('\n') | ||
.filter(isErrorLine) | ||
.splice(1) // trim 1st line | ||
.splice(1) // trim 1st line | ||
.join('\n') | ||
.replace(/ \[[A-Z_]+\]/g, ''); // trim error categories | ||
.replace(/ \[[A-Z_]+\]/g, ''); // trim error categories | ||
execFile( | ||
@@ -261,7 +272,7 @@ process.execPath, | ||
'amp4ads_feature_tests/style-amp-custom.html', | ||
'amp4ads_feature_tests/min_valid_amp4ads.html' | ||
'amp4ads_feature_tests/min_valid_amp4ads.html', | ||
], | ||
{'cwd': '../testdata'}, // Run inside the testdata dir to match paths. | ||
{'cwd': '../testdata'}, // Run inside the testdata dir to match paths. | ||
function(error, stdout, stderr) { | ||
expect(error).toBeDefined(); // At least one file had errors. | ||
expect(error).toBeDefined(); // At least one file had errors. | ||
expect(stderr).toBe(severalErrorsOut); | ||
@@ -268,0 +279,0 @@ expect(stdout).toBe( |
176
index.js
@@ -21,21 +21,21 @@ #!/usr/bin/env node | ||
var Promise = require('promise'); | ||
var colors = require('colors'); | ||
var fs = require('fs'); | ||
var http = require('http'); | ||
var https = require('https'); | ||
var path = require('path'); | ||
var program = require('commander'); | ||
var querystring = require('querystring'); | ||
var url = require('url'); | ||
var util = require('util'); | ||
var vm = require('vm'); | ||
const colors = require('colors'); | ||
const fs = require('fs'); | ||
const http = require('http'); | ||
const https = require('https'); | ||
const path = require('path'); | ||
const program = require('commander'); | ||
const Promise = require('promise'); | ||
const querystring = require('querystring'); | ||
const url = require('url'); | ||
const util = require('util'); | ||
const vm = require('vm'); | ||
var DEFAULT_USER_AGENT = 'amphtml-validator'; | ||
const DEFAULT_USER_AGENT = 'amphtml-validator'; | ||
/** | ||
* Determines if str begins with prefix. | ||
* @param {!string} str | ||
* @param {!string} prefix | ||
* @returns {!boolean} | ||
* @param {string} str | ||
* @param {string} prefix | ||
* @return {boolean} | ||
*/ | ||
@@ -49,4 +49,4 @@ function hasPrefix(str, prefix) { | ||
* it may be a local file. | ||
* @param {!string} url | ||
* @returns {!boolean} | ||
* @param {string} url | ||
* @return {boolean} | ||
*/ | ||
@@ -59,4 +59,4 @@ function isHttpOrHttpsUrl(url) { | ||
* Creates a promise which reads from a file. | ||
* @param {!string} name | ||
* @returns {!Promise<!string>} | ||
* @param {string} name | ||
* @return {Promise<string>} | ||
*/ | ||
@@ -77,9 +77,9 @@ function readFromFile(name) { | ||
* Creates a promise which reads from a stream. | ||
* @param {!string} name | ||
* @param {string} name | ||
* @param {!stream.Readable} readable | ||
* @returns {!Promise<!string>} | ||
* @return {Promise<string>} | ||
*/ | ||
function readFromReadable(name, readable) { | ||
return new Promise(function(resolve, reject) { | ||
var chunks = []; | ||
const chunks = []; | ||
readable.setEncoding('utf8'); | ||
@@ -102,3 +102,3 @@ readable.on('data', function(chunk) { | ||
* for consistency with readFromUrl and readFromFile. | ||
* @returns {!Promise<!string>} | ||
* @return {Promise<string>} | ||
*/ | ||
@@ -116,32 +116,32 @@ function readFromStdin() { | ||
* Any HTTP status other than 200 is interpreted as an error. | ||
* @param {!string} url | ||
* @param {!string} userAgent | ||
* @returns {!Promise<!string>} | ||
* @param {string} url | ||
* @param {string} userAgent | ||
* @return {Promise<string>} | ||
*/ | ||
function readFromUrl(url, userAgent) { | ||
return new Promise(function(resolve, reject) { | ||
var clientModule = hasPrefix(url, 'http://') ? http : https; | ||
var req = clientModule.request(url, function(response) { | ||
if (response.statusCode !== 200) { | ||
// https://nodejs.org/api/http.html says: "[...] However, if | ||
// you add a 'response' event handler, then you must consume | ||
// the data from the response object, either by calling | ||
// response.read() whenever there is a 'readable' event, or by | ||
// adding a 'data' handler, or by calling the .resume() | ||
// method." | ||
response.resume(); | ||
reject(new Error( | ||
'Unable to fetch ' + url + ' - HTTP Status ' + | ||
const clientModule = hasPrefix(url, 'http://') ? http : https; | ||
const req = clientModule.request(url, function(response) { | ||
if (response.statusCode !== 200) { | ||
// https://nodejs.org/api/http.html says: "[...] However, if | ||
// you add a 'response' event handler, then you must consume | ||
// the data from the response object, either by calling | ||
// response.read() whenever there is a 'readable' event, or by | ||
// adding a 'data' handler, or by calling the .resume() | ||
// method." | ||
response.resume(); | ||
reject(new Error( | ||
'Unable to fetch ' + url + ' - HTTP Status ' + | ||
response.statusCode)); | ||
} else { | ||
resolve(response); | ||
} | ||
}); | ||
req.setHeader('User-Agent', userAgent); | ||
req.on('error', function(error) { // E.g., DNS resolution errors. | ||
reject( | ||
new Error('Unable to fetch ' + url + ' - ' + error.message)); | ||
}); | ||
req.end(); | ||
}) | ||
} else { | ||
resolve(response); | ||
} | ||
}); | ||
req.setHeader('User-Agent', userAgent); | ||
req.on('error', function(error) { // E.g., DNS resolution errors. | ||
reject( | ||
new Error('Unable to fetch ' + url + ' - ' + error.message)); | ||
}); | ||
req.end(); | ||
}) | ||
.then(readFromReadable.bind(null, url)); | ||
@@ -161,3 +161,3 @@ } | ||
* Possible values are 'UNKNOWN', 'PASS', and 'FAIL'. | ||
* @type {!string} | ||
* @type {string} | ||
*/ | ||
@@ -195,3 +195,3 @@ this.status = 'UNKNOWN'; | ||
* fields below. | ||
* @type {!string} | ||
* @type {string} | ||
*/ | ||
@@ -203,3 +203,3 @@ this.message = ''; | ||
* as a "Learn more" link. | ||
* @type {!string} | ||
* @type {string} | ||
*/ | ||
@@ -212,3 +212,3 @@ this.specUrl = null; | ||
* See the ErrorCategory.Code enum in validator.proto for possible values. | ||
* @type {!string} | ||
* @type {string} | ||
*/ | ||
@@ -225,3 +225,3 @@ this.category = 'UNKNOWN'; | ||
* which is used to assemble the message from the strings in params. | ||
* @type {!string} | ||
* @type {string} | ||
*/ | ||
@@ -233,3 +233,3 @@ this.code = 'UNKNOWN_CODE'; | ||
* for humans to read over the message field (see above). | ||
* @type {!Array<!string>} | ||
* @type {!Array<string>} | ||
*/ | ||
@@ -244,3 +244,3 @@ this.params = []; | ||
* local file. | ||
* @param {!string} scriptContents | ||
* @param {string} scriptContents | ||
* @throws {!Error} | ||
@@ -271,15 +271,15 @@ * @constructor | ||
* 'AMP4ADS'; it defaults to 'AMP' if not specified. | ||
* @param {!string} inputString | ||
* @param {string} inputString | ||
* @param {string=} htmlFormat | ||
* @returns {!ValidationResult} | ||
* @return {!ValidationResult} | ||
* @export | ||
*/ | ||
Validator.prototype.validateString = function(inputString, htmlFormat) { | ||
var internalResult = | ||
const internalResult = | ||
this.sandbox.amp.validator.validateString(inputString, htmlFormat); | ||
var result = new ValidationResult(); | ||
const result = new ValidationResult(); | ||
result.status = internalResult.status; | ||
for (var ii = 0; ii < internalResult.errors.length; ii++) { | ||
var internalError = internalResult.errors[ii]; | ||
var error = new ValidationError(); | ||
for (let ii = 0; ii < internalResult.errors.length; ii++) { | ||
const internalError = internalResult.errors[ii]; | ||
const error = new ValidationError(); | ||
error.severity = internalError.severity; | ||
@@ -304,3 +304,3 @@ error.line = internalError.line; | ||
*/ | ||
var instanceByValidatorJs = {}; | ||
const instanceByValidatorJs = {}; | ||
@@ -316,17 +316,17 @@ /** | ||
* @param {string=} opt_userAgent | ||
* @returns {!Promise<Validator>} | ||
* @return {!Promise<Validator>} | ||
* @export | ||
*/ | ||
function getInstance(opt_validatorJs, opt_userAgent) { | ||
var validatorJs = | ||
const validatorJs = | ||
opt_validatorJs || 'https://cdn.ampproject.org/v0/validator.js'; | ||
var userAgent = opt_userAgent || DEFAULT_USER_AGENT; | ||
const userAgent = opt_userAgent || DEFAULT_USER_AGENT; | ||
if (instanceByValidatorJs.hasOwnProperty(validatorJs)) { | ||
return Promise.resolve(instanceByValidatorJs[validatorJs]); | ||
} | ||
var validatorJsPromise = isHttpOrHttpsUrl(validatorJs) ? | ||
readFromUrl(validatorJs, userAgent) : | ||
readFromFile(validatorJs); | ||
const validatorJsPromise = isHttpOrHttpsUrl(validatorJs) ? | ||
readFromUrl(validatorJs, userAgent) : | ||
readFromFile(validatorJs); | ||
return validatorJsPromise.then(function(scriptContents) { | ||
var instance; | ||
let instance; | ||
try { | ||
@@ -356,3 +356,3 @@ instance = new Validator(scriptContents); | ||
* @param {string} validatorJsContents | ||
* @returns {!Validator} | ||
* @return {!Validator} | ||
* @export | ||
@@ -378,3 +378,3 @@ */ | ||
* process.stderr as is appropriate. | ||
* @param {!string} filename | ||
* @param {string} filename | ||
* @param {!ValidationResult} validationResult | ||
@@ -388,5 +388,5 @@ * @param {boolean} color | ||
} | ||
for (var ii = 0; ii < validationResult.errors.length; ii++) { | ||
var error = validationResult.errors[ii]; | ||
var msg = filename + ':' + error.line + ':' + error.col + ' '; | ||
for (let ii = 0; ii < validationResult.errors.length; ii++) { | ||
const error = validationResult.errors[ii]; | ||
let msg = filename + ':' + error.line + ':' + error.col + ' '; | ||
if (color) { | ||
@@ -426,3 +426,3 @@ msg += (error.severity === 'ERROR' ? colors.red : colors.magenta)( | ||
.option( | ||
'--html_format <AMP|AMP4ADS|AMP4EMAIL|EXPERIMENTAL>', | ||
'--html_format <AMP|AMP4ADS|AMP4EMAIL|ACTIONS>', | ||
'The input format to be validated.\n' + | ||
@@ -448,6 +448,6 @@ ' AMP by default.', | ||
program.html_format !== 'AMP4EMAIL' && | ||
program.html_format !== 'EXPERIMENTAL') { | ||
program.html_format !== 'ACTIONS') { | ||
process.stderr.write( | ||
'--html_format must be set to "AMP", "AMP4ADS", "AMP4EMAIL", or ' + | ||
'"EXPERIMENTAL.\n', | ||
'"ACTIONS.\n', | ||
function() { | ||
@@ -464,5 +464,5 @@ process.exit(1); | ||
} | ||
var inputs = []; | ||
for (var ii = 0; ii < program.args.length; ii++) { | ||
var item = program.args[ii]; | ||
const inputs = []; | ||
for (let ii = 0; ii < program.args.length; ii++) { | ||
const item = program.args[ii]; | ||
if (item === '-') { | ||
@@ -480,6 +480,6 @@ inputs.push(readFromStdin()); | ||
.then(function(resolvedInputs) { | ||
var jsonOut = {}; | ||
var hasError = false; | ||
for (var ii = 0; ii < resolvedInputs.length; ii++) { | ||
var validationResult = validator.validateString( | ||
const jsonOut = {}; | ||
let hasError = false; | ||
for (let ii = 0; ii < resolvedInputs.length; ii++) { | ||
const validationResult = validator.validateString( | ||
resolvedInputs[ii], program.html_format); | ||
@@ -515,3 +515,3 @@ if (program.format === 'json') { | ||
(program.format == 'color' ? colors.red(error.message) : | ||
error.message) + | ||
error.message) + | ||
'\n', | ||
@@ -526,3 +526,3 @@ function() { | ||
(program.format == 'color' ? colors.red(error.message) : | ||
error.message) + | ||
error.message) + | ||
'\n', | ||
@@ -529,0 +529,0 @@ function() { |
{ | ||
"name": "amphtml-validator", | ||
"version": "1.0.23", | ||
"version": "1.0.24", | ||
"description": "Official validator for AMP HTML (www.ampproject.org)", | ||
@@ -13,3 +13,3 @@ "keywords": [ | ||
"engines": { | ||
"node": ">=0.10.25" | ||
"node": "^10.0.0" | ||
}, | ||
@@ -25,10 +25,13 @@ "author": "The AMP HTML Authors", | ||
}, | ||
"scripts": { | ||
"preinstall": "node ../../build-system/common/check-package-manager.js" | ||
}, | ||
"dependencies": { | ||
"colors": "1.1.2", | ||
"commander": "2.9.0", | ||
"promise": "7.1.1" | ||
"colors": "1.2.5", | ||
"commander": "2.15.1", | ||
"promise": "8.0.1" | ||
}, | ||
"devDependencies": { | ||
"jasmine": "2.3.2" | ||
"jasmine": "3.1.0" | ||
} | ||
} |
@@ -12,3 +12,3 @@ # amphtml-validator Node.js Package | ||
The `amphtml-validator` command line tool is documented here: | ||
https://www.ampproject.org/docs/guides/validate.html#command-line-tool | ||
https://amp.dev/documentation/guides-and-tutorials/learn/validation-workflow/validate_amp#command-line-tool | ||
@@ -45,4 +45,4 @@ ## Node.js API | ||
FAIL | ||
line 1, col 0: The mandatory attribute '⚡' is missing in tag 'html ⚡ for top-level html'. (see https://www.ampproject.org/docs/reference/spec.html#required-markup) | ||
line 1, col 0: The parent tag of tag 'html ⚡ for top-level html' is '$root', but it can only be '!doctype'. (see https://www.ampproject.org/docs/reference/spec.html#required-markup) | ||
line 1, col 0: The mandatory attribute '⚡' is missing in tag 'html ⚡ for top-level html'. (see https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#required-markup) | ||
line 1, col 0: The parent tag of tag 'html ⚡ for top-level html' is '$root', but it can only be '!doctype'. (see https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml.html#required-markup) | ||
... | ||
@@ -49,0 +49,0 @@ ``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
31398
1
+ Addedcolors@1.2.5(transitive)
+ Addedcommander@2.15.1(transitive)
+ Addedpromise@8.0.1(transitive)
- Removedcolors@1.1.2(transitive)
- Removedcommander@2.9.0(transitive)
- Removedgraceful-readlink@1.0.1(transitive)
- Removedpromise@7.1.1(transitive)
Updatedcolors@1.2.5
Updatedcommander@2.15.1
Updatedpromise@8.0.1