Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validator Rollup #7844

Merged
merged 8 commits into from
Mar 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 120 additions & 61 deletions validator/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,12 @@ def CheckPrereqs():
'Please feel free to edit the source and fix it to your needs.')

# Ensure source files are available.
for f in ['validator-main.protoascii', 'validator.proto',
'validator_gen_js.py', 'package.json', 'engine/validator.js',
'engine/validator_test.js', 'engine/validator-in-browser.js',
'engine/tokenize-css.js', 'engine/parse-css.js',
'engine/parse-srcset.js', 'engine/parse-url.js']:
for f in [
'validator-main.protoascii', 'validator.proto', 'validator_gen_js.py',
'package.json', 'engine/validator.js', 'engine/validator_test.js',
'engine/validator-in-browser.js', 'engine/tokenize-css.js',
'engine/parse-css.js', 'engine/parse-srcset.js', 'engine/parse-url.js'
]:
if not os.path.exists(f):
Die('%s not found. Must run in amp_validator source directory.' % f)

Expand Down Expand Up @@ -146,8 +147,8 @@ def GenValidatorPb2Py(out_dir):
logging.info('entering ...')
assert re.match(r'^[a-zA-Z_\-0-9]+$', out_dir), 'bad out_dir: %s' % out_dir

subprocess.check_call(['protoc', 'validator.proto',
'--python_out=%s' % out_dir])
subprocess.check_call(
['protoc', 'validator.proto', '--python_out=%s' % out_dir])
open('%s/__init__.py' % out_dir, 'w').close()
logging.info('... done')

Expand Down Expand Up @@ -199,6 +200,8 @@ def GenValidatorGeneratedJs(out_dir):
specfile='%s/validator.protoascii' % out_dir,
validator_pb2=validator_pb2,
text_format=text_format,
html_format=None,
light=False,
descriptor=descriptor,
out=out)
out.append('')
Expand All @@ -208,6 +211,39 @@ def GenValidatorGeneratedJs(out_dir):
logging.info('... done')


def GenValidatorGeneratedLightAmpJs(out_dir):
"""Calls validator_gen_js to generate validator-generated-light-amp.js.

Args:
out_dir: directory name of the output directory. Must not have slashes,
dots, etc.
"""
logging.info('entering ...')
assert re.match(r'^[a-zA-Z_\-0-9]+$', out_dir), 'bad out_dir: %s' % out_dir

# These imports happen late, within this method because they don't necessarily
# exist when the module starts running, and the ones that probably do
# are checked by CheckPrereqs.
from google.protobuf import text_format
from google.protobuf import descriptor
from dist import validator_pb2
import validator_gen_js
out = []
validator_gen_js.GenerateValidatorGeneratedJs(
specfile='%s/validator.protoascii' % out_dir,
validator_pb2=validator_pb2,
text_format=text_format,
html_format=validator_pb2.TagSpec.AMP,
light=True,
descriptor=descriptor,
out=out)
out.append('')
f = open('%s/validator-generated-light-amp.js' % out_dir, 'w')
f.write('\n'.join(out))
f.close()
logging.info('... done')


def GenValidatorGeneratedMd(out_dir):
"""Calls validator_gen_md to generate validator-generated.md.

Expand Down Expand Up @@ -246,14 +282,18 @@ def CompileWithClosure(js_files, closure_entry_points, output_file):
output_file: name of the Javascript output file
"""

cmd = ['java', '-jar', 'node_modules/google-closure-compiler/compiler.jar',
'--language_in=ECMASCRIPT6_STRICT', '--language_out=ES5_STRICT',
'--js_output_file=%s' % output_file, '--only_closure_dependencies']
cmd = [
'java', '-jar', 'node_modules/google-closure-compiler/compiler.jar',
'--language_in=ECMASCRIPT6_STRICT', '--language_out=ES5_STRICT',
'--js_output_file=%s' % output_file, '--only_closure_dependencies'
]
cmd += ['--closure_entry_point=%s' % e for e in closure_entry_points]
cmd += ['node_modules/google-closure-library/closure/**.js',
'!node_modules/google-closure-library/closure/**_test.js',
'node_modules/google-closure-library/third_party/closure/**.js',
'!node_modules/google-closure-library/third_party/closure/**_test.js']
cmd += [
'node_modules/google-closure-library/closure/**.js',
'!node_modules/google-closure-library/closure/**_test.js',
'node_modules/google-closure-library/third_party/closure/**.js',
'!node_modules/google-closure-library/third_party/closure/**_test.js'
]
cmd += js_files
subprocess.check_call(cmd)

Expand All @@ -266,16 +306,19 @@ def CompileValidatorMinified(out_dir):
"""
logging.info('entering ...')
CompileWithClosure(
js_files=['engine/htmlparser.js', 'engine/parse-css.js',
'engine/parse-srcset.js', 'engine/parse-url.js',
'engine/tokenize-css.js',
'%s/validator-generated.js' % out_dir,
'engine/validator-in-browser.js', 'engine/validator.js',
'engine/amp4ads-parse-css.js', 'engine/dom-walker.js',
'engine/htmlparser-interface.js'],
closure_entry_points=['amp.validator.validateString',
'amp.validator.renderValidationResult',
'amp.validator.renderErrorMessage'],
js_files=[
'engine/htmlparser.js', 'engine/parse-css.js',
'engine/parse-srcset.js', 'engine/parse-url.js',
'engine/tokenize-css.js', '%s/validator-generated.js' % out_dir,
'engine/validator-in-browser.js', 'engine/validator.js',
'engine/amp4ads-parse-css.js', 'engine/dom-walker.js',
'engine/htmlparser-interface.js'
],
closure_entry_points=[
'amp.validator.validateString',
'amp.validator.renderValidationResult',
'amp.validator.renderErrorMessage'
],
output_file='%s/validator_minified.js' % out_dir)
logging.info('... done')

Expand All @@ -290,9 +333,11 @@ def RunSmokeTest(out_dir, nodejs_cmd):
logging.info('entering ...')
# Run index.js on the minimum valid amp and observe that it passes.
p = subprocess.Popen(
[nodejs_cmd, 'nodejs/index.js', '--validator_js',
'%s/validator_minified.js' % out_dir,
'testdata/feature_tests/minimum_valid_amp.html'],
[
nodejs_cmd, 'nodejs/index.js', '--validator_js',
'%s/validator_minified.js' % out_dir,
'testdata/feature_tests/minimum_valid_amp.html'
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(stdout, stderr) = p.communicate()
Expand All @@ -303,9 +348,11 @@ def RunSmokeTest(out_dir, nodejs_cmd):

# Run index.js on an empty file and observe that it fails.
p = subprocess.Popen(
[nodejs_cmd, 'nodejs/index.js', '--validator_js',
'%s/validator_minified.js' % out_dir,
'testdata/feature_tests/empty.html'],
[
nodejs_cmd, 'nodejs/index.js', '--validator_js',
'%s/validator_minified.js' % out_dir,
'testdata/feature_tests/empty.html'
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(stdout, stderr) = p.communicate()
Expand Down Expand Up @@ -345,13 +392,14 @@ def CompileValidatorTestMinified(out_dir):
"""
logging.info('entering ...')
CompileWithClosure(
js_files=['engine/htmlparser.js', 'engine/parse-css.js',
'engine/parse-srcset.js', 'engine/parse-url.js',
'engine/tokenize-css.js',
'%s/validator-generated.js' % out_dir,
'engine/validator-in-browser.js', 'engine/validator.js',
'engine/amp4ads-parse-css.js', 'engine/htmlparser-interface.js',
'engine/dom-walker.js', 'engine/validator_test.js'],
js_files=[
'engine/htmlparser.js', 'engine/parse-css.js',
'engine/parse-srcset.js', 'engine/parse-url.js',
'engine/tokenize-css.js', '%s/validator-generated.js' % out_dir,
'engine/validator-in-browser.js', 'engine/validator.js',
'engine/amp4ads-parse-css.js', 'engine/htmlparser-interface.js',
'engine/dom-walker.js', 'engine/validator_test.js'
],
closure_entry_points=['amp.validator.ValidatorTest'],
output_file='%s/validator_test_minified.js' % out_dir)
logging.info('... success')
Expand All @@ -366,12 +414,14 @@ def CompileValidatorLightTestMinified(out_dir):
"""
logging.info('entering ...')
CompileWithClosure(
js_files=['engine/htmlparser.js', 'engine/parse-css.js',
'engine/parse-srcset.js', 'engine/parse-url.js',
'engine/tokenize-css.js', '%s/validator-generated.js' % out_dir,
'engine/validator-in-browser.js', 'engine/validator.js',
'engine/amp4ads-parse-css.js', 'engine/htmlparser-interface.js',
'engine/dom-walker.js', 'engine/validator-light_test.js'],
js_files=[
'engine/htmlparser.js', 'engine/parse-css.js',
'engine/parse-srcset.js', 'engine/parse-url.js',
'engine/tokenize-css.js', '%s/validator-generated-light-amp.js' %
out_dir, 'engine/validator-in-browser.js', 'engine/validator.js',
'engine/amp4ads-parse-css.js', 'engine/htmlparser-interface.js',
'engine/dom-walker.js', 'engine/validator-light_test.js'
],
closure_entry_points=['amp.validator.ValidatorTest'],
output_file='%s/validator-light_test_minified.js' % out_dir)
logging.info('... success')
Expand All @@ -386,8 +436,10 @@ def CompileHtmlparserTestMinified(out_dir):
"""
logging.info('entering ...')
CompileWithClosure(
js_files=['engine/htmlparser.js', 'engine/htmlparser-interface.js',
'engine/htmlparser_test.js'],
js_files=[
'engine/htmlparser.js', 'engine/htmlparser-interface.js',
'engine/htmlparser_test.js'
],
closure_entry_points=['amp.htmlparser.HtmlParserTest'],
output_file='%s/htmlparser_test_minified.js' % out_dir)
logging.info('... success')
Expand All @@ -402,10 +454,12 @@ def CompileParseCssTestMinified(out_dir):
"""
logging.info('entering ...')
CompileWithClosure(
js_files=['engine/parse-css.js', 'engine/parse-url.js',
'engine/tokenize-css.js', 'engine/css-selectors.js',
'engine/json-testutil.js', 'engine/parse-css_test.js',
'%s/validator-generated.js' % out_dir],
js_files=[
'engine/parse-css.js', 'engine/parse-url.js',
'engine/tokenize-css.js', 'engine/css-selectors.js',
'engine/json-testutil.js', 'engine/parse-css_test.js',
'%s/validator-generated.js' % out_dir
],
closure_entry_points=['parse_css.ParseCssTest'],
output_file='%s/parse-css_test_minified.js' % out_dir)
logging.info('... success')
Expand All @@ -420,10 +474,12 @@ def CompileParseUrlTestMinified(out_dir):
"""
logging.info('entering ...')
CompileWithClosure(
js_files=['engine/parse-url.js', 'engine/parse-css.js',
'engine/tokenize-css.js', 'engine/css-selectors.js',
'engine/json-testutil.js', 'engine/parse-url_test.js',
'%s/validator-generated.js' % out_dir],
js_files=[
'engine/parse-url.js', 'engine/parse-css.js',
'engine/tokenize-css.js', 'engine/css-selectors.js',
'engine/json-testutil.js', 'engine/parse-url_test.js',
'%s/validator-generated.js' % out_dir
],
closure_entry_points=['parse_url.ParseURLTest'],
output_file='%s/parse-url_test_minified.js' % out_dir)
logging.info('... success')
Expand All @@ -438,11 +494,12 @@ def CompileAmp4AdsParseCssTestMinified(out_dir):
"""
logging.info('entering ...')
CompileWithClosure(
js_files=['engine/amp4ads-parse-css_test.js', 'engine/parse-css.js',
'engine/parse-url.js', 'engine/amp4ads-parse-css.js',
'engine/tokenize-css.js', 'engine/css-selectors.js',
'engine/json-testutil.js',
'%s/validator-generated.js' % out_dir],
js_files=[
'engine/amp4ads-parse-css_test.js', 'engine/parse-css.js',
'engine/parse-url.js', 'engine/amp4ads-parse-css.js',
'engine/tokenize-css.js', 'engine/css-selectors.js',
'engine/json-testutil.js', '%s/validator-generated.js' % out_dir
],
closure_entry_points=['parse_css.Amp4AdsParseCssTest'],
output_file='%s/amp4ads-parse-css_test_minified.js' % out_dir)
logging.info('... success')
Expand All @@ -457,9 +514,10 @@ def CompileParseSrcsetTestMinified(out_dir):
"""
logging.info('entering ...')
CompileWithClosure(
js_files=['engine/parse-srcset.js', 'engine/json-testutil.js',
'engine/parse-srcset_test.js',
'%s/validator-generated.js' % out_dir],
js_files=[
'engine/parse-srcset.js', 'engine/json-testutil.js',
'engine/parse-srcset_test.js', '%s/validator-generated.js' % out_dir
],
closure_entry_points=['parse_srcset.ParseSrcsetTest'],
output_file='%s/parse-srcset_test_minified.js' % out_dir)
logging.info('... success')
Expand Down Expand Up @@ -527,6 +585,7 @@ def Main():
GenValidatorPb2Py(out_dir='dist')
GenValidatorProtoascii(out_dir='dist')
GenValidatorGeneratedJs(out_dir='dist')
GenValidatorGeneratedLightAmpJs(out_dir='dist')
GenValidatorGeneratedMd(out_dir='dist')
CompileValidatorMinified(out_dir='dist')
RunSmokeTest(out_dir='dist', nodejs_cmd=nodejs_cmd)
Expand Down
23 changes: 23 additions & 0 deletions validator/engine/amp4ads-parse-css.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
goog.provide('parse_css.stripVendorPrefix');
goog.provide('parse_css.validateAmp4AdsCss');

goog.require('amp.validator.LIGHT');
goog.require('amp.validator.ValidationError');
goog.require('parse_css.DelimToken');
goog.require('parse_css.ErrorToken');
goog.require('parse_css.IdentToken');
goog.require('parse_css.RuleVisitor');
goog.require('parse_css.Stylesheet');
goog.require('parse_css.TRIVIAL_ERROR_TOKEN');

/**
* Strips vendor prefixes from identifiers, e.g. property names or names
Expand Down Expand Up @@ -115,6 +118,10 @@ class Amp4AdsVisitor extends parse_css.RuleVisitor {
}
const ident = firstIdent(declaration.value);
if (ident === 'fixed' || ident === 'sticky') {
if (amp.validator.LIGHT) {
this.errors.push(parse_css.TRIVIAL_ERROR_TOKEN);
return;
}
this.errors.push(createParseErrorTokenAt(
declaration, amp.validator.ValidationError.Code
.CSS_SYNTAX_DISALLOWED_PROPERTY_VALUE,
Expand Down Expand Up @@ -142,6 +149,10 @@ class Amp4AdsVisitor extends parse_css.RuleVisitor {
parse_css.stripVendorPrefix(transitionedProperty);
if (transitionedPropertyStripped !== 'opacity' &&
transitionedPropertyStripped !== 'transform') {
if (amp.validator.LIGHT) {
this.errors.push(parse_css.TRIVIAL_ERROR_TOKEN);
return;
}
this.errors.push(createParseErrorTokenAt(
decl, amp.validator.ValidationError.Code
.CSS_SYNTAX_DISALLOWED_PROPERTY_VALUE_WITH_HINT,
Expand All @@ -155,6 +166,10 @@ class Amp4AdsVisitor extends parse_css.RuleVisitor {
// the only properties that may be transitioned are opacity and transform.
if (this.inKeyframes !== null && name !== 'transform' &&
name !== 'opacity') {
if (amp.validator.LIGHT) {
this.errors.push(parse_css.TRIVIAL_ERROR_TOKEN);
return;
}
this.errors.push(createParseErrorTokenAt(
decl, amp.validator.ValidationError.Code
.CSS_SYNTAX_PROPERTY_DISALLOWED_WITHIN_AT_RULE,
Expand All @@ -178,6 +193,10 @@ class Amp4AdsVisitor extends parse_css.RuleVisitor {
if (allowed.indexOf(parse_css.stripVendorPrefix(decl.name)) !== -1) {
continue;
}
if (amp.validator.LIGHT) {
this.errors.push(parse_css.TRIVIAL_ERROR_TOKEN);
return;
}
this.errors.push(createParseErrorTokenAt(
decl, amp.validator.ValidationError.Code
.CSS_SYNTAX_PROPERTY_DISALLOWED_TOGETHER_WITH,
Expand All @@ -188,6 +207,10 @@ class Amp4AdsVisitor extends parse_css.RuleVisitor {
}
// (2) Check that the rule is qualified with .amp-animate.
if (!hasAmpAnimate(qualifiedRule)) {
if (amp.validator.LIGHT) {
this.errors.push(parse_css.TRIVIAL_ERROR_TOKEN);
return;
}
this.errors.push(createParseErrorTokenAt(
qualifiedRule, amp.validator.ValidationError.Code
.CSS_SYNTAX_PROPERTY_REQUIRES_QUALIFICATION,
Expand Down
Loading