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

Compile error when class name begins with dash followed by number. #2907

Closed
meatcar opened this issue Nov 17, 2017 · 5 comments
Closed

Compile error when class name begins with dash followed by number. #2907

meatcar opened this issue Nov 17, 2017 · 5 comments

Comments

@meatcar
Copy link
Contributor

meatcar commented Nov 17, 2017

Pug Version: 2.0.0-rc.4

Node Version: v8.9.1

Input JavaScript Values

pug.renderFile('input.pug', {});

Input Pug

.-1u Some Content

Expected HTML

<div class="-1u">Some Content</div>

Actual HTML

Error: /usr/src/app/input.pug:10:24

     > 1|       .-1u Some Content
    --------------^
    If a class name begins with a "-" or "--", it must be followed by a letter or underscore.
       at makeError (/usr/src/app/node_modules/pug-error/index.js:32:13)
       at Lexer.error (/usr/src/app/node_modules/pug-lexer/index.js:58:15)
       at Lexer.className (/usr/src/app/node_modules/pug-lexer/index.js:413:12)
       at Lexer.callLexerFunction (/usr/src/app/node_modules/pug-lexer/index.js:1319:23)
       at Lexer.advance (/usr/src/app/node_modules/pug-lexer/index.js:1355:15)
       at Lexer.callLexerFunction (/usr/src/app/node_modules/pug-lexer/index.js:1319:23)
       at Lexer.getTokens (/usr/src/app/node_modules/pug-lexer/index.js:1375:12)
       at lex (/usr/src/app/node_modules/pug-lexer/index.js:12:42)
       at Object.lex (/usr/src/app/node_modules/pug/lib/index.js:99:27)
       at Function.loadString [as string] (/usr/src/app/node_modules/pug-load/index.js:44:24)
       at compileBody (/usr/src/app/node_modules/pug/lib/index.js:86:18)
       at Object.exports.compile (/usr/src/app/node_modules/pug/lib/index.js:243:16)
       at handleTemplateCache (/usr/src/app/node_modules/pug/lib/index.js:216:25)
       at Object.exports.renderFile (/usr/src/app/node_modules/pug/lib/index.js:428:10)
       at Object.exports.renderFile (/usr/src/app/node_modules/pug/lib/index.js:418:21)
       at View.exports.__express [as engine] (/usr/src/app/node_modules/pug/lib/index.js:465:11)
       at runCallback (timers.js:785:20)
       at tryOnImmediate (timers.js:747:5)
       at processImmediate [as _immediateCallback] (timers.js:718:5)

Additional Comments

I'm supporting an applicatin that is using https://github.com/ajlkn/skel as a grid framework, which uses classes like 6u and -6u to designate columns and offsets respectively. AFAIK those are not valid classes according to spec, but they used to work ok with jade.

I'm migrating from jade to pug, and am running into this compile error. It's pretty show-stopping, re-writing all the views to use a different grid framework would be very painful. We haven't had any rendering issues with any modern browsers due to using off-spec class names.

@droooney
Copy link
Member

You can use the following syntax:

div(class="-1u") Some Content

@meatcar
Copy link
Contributor Author

meatcar commented Nov 18, 2017

That is an option, but we would still have to rewrite a lot of code to do the migration, vs just changing a single regexp to allow class names to have numbers after a dash. That wouldn't conflict with any other pug syntax, make the templates less verbose (one of pug's main selling points), and would make some users very happy :)

@droooney
Copy link
Member

It does sound that it won't hurt anyone and doesn't violate any other syntax. But solving this case would be only a half measure, because technically you can use any unicode character in your HTML class name.

If the syntax should be extended, it probably should allow any characters except for ., #, &, braces, whitespace characters and maybe a couple of other characters that may become a part of the future pug syntax. The id syntax should probably be extended in this case as well.

@ForbesLindesay @TimothyGu any thoughts?

@jbsulli
Copy link
Contributor

jbsulli commented Nov 18, 2017

Please no. Using a dash (or other odd char) at the beginning of a class literal makes it look like there is something strange/fancy going on. Class and Id literals are what make pug so clean and readable. Allowing other characters will make it difficult to parse and understand.

That being said... it looks like we allow one or two dashes at the beginning of classes now??? This is odd... seems like if we are going to allow dashes, allow infinite dashes. Allowing numbers at this point doesn't seem like a big deal. But for funky use cases like this, instead of making the project more convoluted, I think we should point people to how they can write a simple plugin for their use case:

const pug = require("pug");

const extendedClassLiteralPlugin = {
    lex: {
        "className": function(lex) {
            var tok = lex.scan(/^\.([_a-z\-0-9][_a-z0-9\-]*)/i, 'class');
            if (tok) {
                lex.tokens.push(tok);
                lex.incrementColumn(tok.val.length);
                return true;
            }
        }
    }
}

pug.render(".-6u Test", { plugins:[extendedClassLiteralPlugin] }, (err, result) => console.log(err || result));

This way, future support for these fringe cases is on them and not bogging down the Pug.js team.

@ForbesLindesay
Copy link
Member

If the syntax should be extended, it probably should allow any characters except for ., #, &

We don't want to do this because it would prevent us adding any new meaning to any special characters without a full breaking change. e.g. in the future we may want to use @ or $ or * for something special. There are already things missing from this list (e.g. !, =) so it's really hard to properly maintain. How about we simplify the requirements in

var tok = this.scan(/^\.(-?-?[_a-z][_a-z0-9\-]*)/i, 'class');
to something like:

var tok = this.scan(/^\.([_a-z0-9\-]*[_a-z][_a-z0-9\-]*)/i, 'class'); 

i.e. must have at least one letter or _ but can have that anywhere in the name. I think this is probably a lot broader than what's technically allowed in the spec, but browsers tend to be fairly permissive.

We'd then need to replace the two error conditions

if (/^\.\-/i.test(this.input)) {
this.error('INVALID_CLASS_NAME', 'If a class name begins with a "-" or "--", it must be followed by a letter or underscore.');
}
if (/^\.[0-9]/i.test(this.input)) {
this.error('INVALID_CLASS_NAME', 'Class names must begin with "-", "_" or a letter.');
}
with one that went something like:

if (/^\.[_a-z0-9\-]+/i.test(this.input)) {
  this.error('INVALID_CLASS_NAME', 'Class names must contain at least one letter or underscore.');
}

If someone sends a pull request for this, along with a test case, I'd be willing to accept.

meatcar added a commit to meatcar/pug that referenced this issue Jan 27, 2018
* Allow class names to begin with single dash, 0-9, a-z, and underscore
* Add test case that passes with change, fails without change

Fixes pugjs#2907
ForbesLindesay pushed a commit that referenced this issue Feb 5, 2018
* Allow class names to begin with single dash, 0-9, a-z, and underscore
* Add test case that passes with change, fails without change

Fixes #2907
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants