-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #193 from hapijs/recursive-descent
Rewrite as a recursive descent parser
- Loading branch information
Showing
9 changed files
with
1,790 additions
and
1,360 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
'use strict'; | ||
|
||
exports.categories = { | ||
valid: 1, | ||
dnsWarn: 7, | ||
rfc5321: 15, | ||
cfws: 31, | ||
deprecated: 63, | ||
rfc5322: 127, | ||
error: 255 | ||
}; | ||
|
||
exports.diagnoses = { | ||
|
||
// Address is valid | ||
|
||
valid: 0, | ||
|
||
// Address is valid for SMTP but has unusual elements | ||
|
||
rfc5321TLD: 9, | ||
rfc5321TLDNumeric: 10, | ||
rfc5321QuotedString: 11, | ||
rfc5321AddressLiteral: 12, | ||
|
||
// Address is valid for message, but must be modified for envelope | ||
|
||
cfwsComment: 17, | ||
cfwsFWS: 18, | ||
|
||
// Address contains non-ASCII when the allowUnicode option is false | ||
// Has to be > internals.defaultThreshold so that it's rejected | ||
// without an explicit errorLevel: | ||
undesiredNonAscii: 25, | ||
|
||
// Address contains deprecated elements, but may still be valid in some contexts | ||
|
||
deprecatedLocalPart: 33, | ||
deprecatedFWS: 34, | ||
deprecatedQTEXT: 35, | ||
deprecatedQP: 36, | ||
deprecatedComment: 37, | ||
deprecatedCTEXT: 38, | ||
deprecatedIPv6: 39, | ||
deprecatedCFWSNearAt: 49, | ||
|
||
// Address is only valid according to broad definition in RFC 5322, but is otherwise invalid | ||
|
||
rfc5322Domain: 65, | ||
rfc5322TooLong: 66, | ||
rfc5322LocalTooLong: 67, | ||
rfc5322DomainTooLong: 68, | ||
rfc5322LabelTooLong: 69, | ||
rfc5322DomainLiteral: 70, | ||
rfc5322DomainLiteralOBSDText: 71, | ||
rfc5322IPv6GroupCount: 72, | ||
rfc5322IPv62x2xColon: 73, | ||
rfc5322IPv6BadCharacter: 74, | ||
rfc5322IPv6MaxGroups: 75, | ||
rfc5322IPv6ColonStart: 76, | ||
rfc5322IPv6ColonEnd: 77, | ||
|
||
// Address is invalid for any purpose | ||
|
||
errExpectingDTEXT: 129, | ||
errNoLocalPart: 130, | ||
errNoDomain: 131, | ||
errConsecutiveDots: 132, | ||
errATEXTAfterCFWS: 133, | ||
errATEXTAfterQS: 134, | ||
errATEXTAfterDomainLiteral: 135, | ||
errExpectingQPair: 136, | ||
errExpectingATEXT: 137, | ||
errExpectingQTEXT: 138, | ||
errExpectingCTEXT: 139, | ||
errBackslashEnd: 140, | ||
errDotStart: 141, | ||
errDotEnd: 142, | ||
errDomainHyphenStart: 143, | ||
errDomainHyphenEnd: 144, | ||
errUnclosedQuotedString: 145, | ||
errUnclosedComment: 146, | ||
errUnclosedDomainLiteral: 147, | ||
errFWSCRLFx2: 148, | ||
errFWSCRLFEnd: 149, | ||
errCRNoLF: 150, | ||
errUnknownTLD: 160, | ||
errDomainTooShort: 161, | ||
errDotAfterDomainLiteral: 162, | ||
errMalformedUnicode: 163 | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
'use strict'; | ||
|
||
// Load modules | ||
|
||
const Constants = require('./constants'); | ||
|
||
/** | ||
* Diagnosis stores a diagnosis-index pair. | ||
*/ | ||
class Diagnosis { | ||
/** | ||
* @param {number} type The diagnostic code. | ||
* @param {number} index The index of the diagnosis. | ||
*/ | ||
constructor(type, index) { | ||
|
||
this.type = type; | ||
this.index = index; | ||
} | ||
} | ||
|
||
|
||
/** | ||
* Diagnoses tracks a set of diagnostic codes for a string, along with their | ||
* positions in the string. | ||
*/ | ||
class Diagnoses { | ||
constructor() { | ||
|
||
this._diagnoses = []; | ||
this._worstDiagnosis = null; | ||
} | ||
|
||
/** | ||
* Report the given diagnosis at the given index. | ||
* | ||
* @param {number} type The diagnosis to report. | ||
* @param {number} index The | ||
*/ | ||
diagnose(type, index) { | ||
|
||
const diagnosis = new Diagnosis(type, index); | ||
|
||
if (this._worstDiagnosis === null || type > this._worstDiagnosis.type) { | ||
this._worstDiagnosis = diagnosis; | ||
} | ||
|
||
this._diagnoses.push(diagnosis); | ||
} | ||
|
||
/** | ||
* Check whether the given diagnosis has been reported. | ||
* | ||
* @param {number} queryType The diagnosis to query. | ||
* @return {boolean} Whether the diagnosis has been reported. | ||
*/ | ||
hasDiagnosis(queryType) { | ||
|
||
return this._diagnoses.some(({ type }) => type === queryType); | ||
} | ||
|
||
/** | ||
* Get the worst diagnosis encountered. | ||
* | ||
* @param {Set<number>=} exclusions The set of diagnoses to exclude per the | ||
* configuration. | ||
* @return {?Diagnosis} The worst diagnosis. | ||
*/ | ||
getWorstDiagnosis(exclusions = new Set()) { | ||
|
||
// Use the precomputed worst diagnosis if it's not excluded. | ||
if (!this._worstDiagnosis || !exclusions.has(this._worstDiagnosis.type)) { | ||
return this._worstDiagnosis; | ||
} | ||
|
||
// Otherwise, find the worst non-excluded diagnosis. | ||
return this._diagnoses.reduce((worst, diagnosis) => { | ||
|
||
if (exclusions.has(diagnosis.type) || (worst && diagnosis.type <= worst.type)) { | ||
return worst; | ||
} | ||
|
||
return diagnosis; | ||
}, null); | ||
} | ||
|
||
/** | ||
* For compatibility with existing versions of isemail, this function gets | ||
* the first fatal diagnosis, or the worst non-fatal diagnosis. | ||
* | ||
* @param {Set<number>} exclusions The set of diagnoses to exclude per the | ||
* configuration. | ||
* @return {?Diagnosis} The backwards-compatible diagnosis. | ||
*/ | ||
getLegacyDiagnosis(exclusions) { | ||
|
||
const firstFatalDiagnosis = this._diagnoses.find(({ type }) => type >= Constants.categories.rfc5322 && !exclusions.has(type)); | ||
|
||
if (firstFatalDiagnosis) { | ||
return firstFatalDiagnosis; | ||
} | ||
|
||
return this.getWorstDiagnosis(exclusions); | ||
} | ||
} | ||
|
||
|
||
module.exports = Diagnoses; |
Oops, something went wrong.