Skip to content

Update to spec version 10.0.0 + Revamp API#11

Merged
Sebmaster merged 2 commits into
jsdom:masterfrom
TimothyGu:feature/rev-18
Jul 27, 2017
Merged

Update to spec version 10.0.0 + Revamp API#11
Sebmaster merged 2 commits into
jsdom:masterfrom
TimothyGu:feature/rev-18

Conversation

@TimothyGu

Copy link
Copy Markdown
Member

Also update and make the entire test suite pass.

Comment thread scripts/generateRegexes.js Outdated
// A.1. ZWNJ, Rule 3
validZWNJ: `(?:${regenerate().add(cp.JT.L).add(cp.JT.D)})(?:${regenerate(cp.JT.T)})*` +
"\\u200C" +
`(?:${regenerate(cp.JT.T)})*(?:${regenerate([...cp.JT.R, ...cp.JT.D])})`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Node v4 doesn't support expansion so this doesn't work. .concat?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I spotted some .includes() usage elsewhere. Maybe best to just require Node v6. That could also allow using default params.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, let's do that. Also allows us to use Array.from for symbol counting.

Comment thread index.js

if (verifyDnsLength) {
const total = labels.slice(0, labels.length - 1).join(".").length;
if (total.length > 253 || total.length === 0) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec says

The length of the domain name, excluding the root label and its dot, is from 1 to 253.

Am I misunderstanding the spec here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

total is already a number -- the length of the domain name excluding the root label and its dot.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I misunderstood your question. This one had me confused as well. The "root label" the spec is referring to is the implied empty label that all domain names have, but is generally omitted with its dot. However it is present in output from tools like dig (note the trailing dot after github.com):

;; QUESTION SECTION:
;github.com.                    IN      A

;; ANSWER SECTION:
github.com.             30      IN      A       192.30.255.113
github.com.             30      IN      A       192.30.255.112

Since it is usually omitted, we don't have to do anything extra to account for that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What'd the root label be in this case? Would it be a TLD, or rather a empty label as in the DNS root zone?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. 👍

Comment thread index.js Outdated
error: true
};
}
if (cp > 0xFFFF) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this one for?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are looking for code points, but the .codePointAt() call against a trailing surrogate returns that surrogate itself. Therefore we have to manually skip that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should only iterate full codepoints here, so I don't think we should ever get to a trailing surrogate?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's take the string "a\uD800\uDC00b". When i = 1, codePointAt returns the code point that's > 0xFFFF. However, without the manual increment, when i = 2 codePointAt would return 0xDC00. That's just how codePointAt works.

We could, however, use for-of loop against the string which would handle this nuance for us.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. Ew, I was not aware of that. I was also not aware for...of for astral strings has been supported for so long in node. Let's use that instead.

Comment thread index.js Outdated
}

if (checkHyphens) {
if (label[2] === "-" && label[3] === "-" ||

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parens here for more clarity

Comment thread index.js
return null;
}

const regexAstralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This breaks countSymbols?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops yeah it seems like it.

Comment thread scripts/generateRegexes.js Outdated
bidiS1RTL: regenerate().add(cp.R).add(cp.AL),

// Step 2
bidiS2: `^(?:${regenerate()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the group in this one at all?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. The output from regenerate() has the format [...]|\u....[...]|\u....[...]. Without the grouping the meaning would change when we append the * operator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment thread index.js Outdated
// 2-4
if (!regexes.bidiS2.test(label) ||
!regexes.bidiS3.test(label) ||
regexes.bidiS4EN.test(label) && regexes.bidiS4AN.test(label)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parens to make this clearer.

Comment thread scripts/generateRegexes.js Outdated
bidiS4AN: regenerate(cp.AN),

// Step 5
bidiS5: `^(?:${regenerate()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Group necessary?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

Comment thread index.js
};
}

if (rtl) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we switch these around and handle ltr (the assumedly more common case) first? Maybe also rename the variable for it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed this order since it's also the order used by the spec, but I'm okay with that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah true. Let's leave it as-is then.

Comment thread index.js
}
}

if (checkJoiners) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the spec link to this one: https://tools.ietf.org/html/rfc5892#appendix-A.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this only a partial implementation in general? What's with all the other characters (non-ZWNJ, non-ZWJ)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other characters in that appendix don't apply to CONTEXTJ. See https://tools.ietf.org/html/rfc5892#appendix-B.1.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's with the chars in Appendix A.3 - A.9?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are for other contexts. See the chart I linked. For example A.3 (U+00B7) is for CONTEXTO.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@Sebmaster

Copy link
Copy Markdown
Member

In general: This is amazing stuff. Thank you so much for this!

@TimothyGu

Copy link
Copy Markdown
Member Author

Converted the entire repo to Node.js v6+, also fixed a couple more test cases so that all of them pass (fixes #6). This should be ready to merge now.

@TimothyGu

Copy link
Copy Markdown
Member Author

Just a note, maybe we should consider revising the API to be a bit more palatable, like (default value after =):

tr46.toASCII(domainName, {
  checkHyphens = false,
  checkBidi = false,
  checkJoiners = false,
  useSTD3ASCIIRules = false,
  // Perhaps also use a string or a symbol that's more self-documenting than a number
  processingOption = tr46.NONTRANSITIONAL,
  verifyDnsLength = false
});

rather than

tr46.toASCII(domainName, useSTD3, processingOption, verifyDnsLength, checkHyphens, checkBidi, checkJoiners);

Compatibility must be broken, of course, but since we are probably releasing a 1.0.0 after this PR anyway, it shouldn't be as big of a concern as it could be.

I'd be happy to implement this change.

@Sebmaster

Copy link
Copy Markdown
Member

Compatibility must be broken, of course, but since we are probably releasing a 1.0.0 after this PR anyway, it shouldn't be as big of a concern as it could be.

Yeah, I think at this point the parameter list is getting a bit too long. Options argument would be very nice.

@Sebmaster Sebmaster left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the code: This is some pretty amazing work.

If you wanna do the options object too, I'll leave it to you, but either way this is good to merge.

@TimothyGu

Copy link
Copy Markdown
Member Author

@Sebmaster done.

Comment thread index.js Outdated
function processing(domainName, useSTD3, checkHyphens, checkBidi, checkJoiners, processingOption) {
function processing(domainName, options) {
const { checkHyphens, checkBidi, checkJoiners, processingOption } = options;
if (processingOption !== TRANSITIONAL && processingOption !== NONTRANSITIONAL) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should do this in the public API, only toASCII requires it I think?

@domenic

domenic commented Jun 17, 2017

Copy link
Copy Markdown
Member

@Sebmaster if we're fixing the public API anyway, WDYT of complying to the usual JS pattern for enums so you can do processingOption: "transitional" / processingOption: "nontransitional"?

@Sebmaster

Copy link
Copy Markdown
Member

Since we're going that way already anyways. Might as well. Provide constants + make them simple strings which may be provided as well?

Comment thread index.js Outdated
checkJoiners = false,
useSTD3ASCIIRules = false,
processingOption = NONTRANSITIONAL,
verifyDnsLength = false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec says VerifyDnsLength, but I'm happy to change this.

@domenic

domenic commented Jun 17, 2017

Copy link
Copy Markdown
Member

I've never been a fan of providing the constants myself but shrug.

@domenic

domenic commented Jun 17, 2017

Copy link
Copy Markdown
Member

As an aside, I wonder why they didn't make transitional processing another boolean flag...

Filed an issue with Unicode: whatwg/url#53 (comment)

@Sebmaster

Copy link
Copy Markdown
Member

Also there are some unused vars now which we can drop?

@TimothyGu

Copy link
Copy Markdown
Member Author

Constants removed.

@Sebmaster

Copy link
Copy Markdown
Member

Seems like lint is still failing because of the unused vars.

@TimothyGu

Copy link
Copy Markdown
Member Author

@Sebmaster Fixed, sorry.

Also:

- Make all tests pass.
- Modernize code base to Node.js v6+.

Fixes: #6
@TimothyGu TimothyGu changed the title Update to latest spec draft Update to spec version 10.0.0 + Revamp API Jun 21, 2017
@TimothyGu

Copy link
Copy Markdown
Member Author

Tables updated to the released 10.0.0 standard.

@TimothyGu

Copy link
Copy Markdown
Member Author

@Sebmaster ping

@Sebmaster Sebmaster merged commit a19e9c5 into jsdom:master Jul 27, 2017
@TimothyGu TimothyGu deleted the feature/rev-18 branch July 28, 2017 00:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants