-
Notifications
You must be signed in to change notification settings - Fork 779
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
36 changed files
with
1,778 additions
and
1,247 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
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
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,51 @@ | ||
/** | ||
* Function which converts given text to `CSSStyleSheet` | ||
* - used in `CSSOM` computation. | ||
* - factory (closure) function, initialized with `document.implementation.createHTMLDocument()`, which uses DOM API for creating `style` elements. | ||
* | ||
* @method axe.utils.getStyleSheetFactory | ||
* @memberof axe.utils | ||
* @param {Object} dynamicDoc `document.implementation.createHTMLDocument() | ||
* @param {Object} options an object with properties to construct stylesheet | ||
* @property {String} options.data text content of the stylesheet | ||
* @property {Boolean} options.isCrossOrigin flag to notify if the resource was fetched from the network | ||
* @property {String} options.shadowId (Optional) shadowId if shadowDOM | ||
* @property {Object} options.root implementation document to create style elements | ||
* @property {String} options.priority a number indicating the loaded priority of CSS, to denote specificity of styles contained in the sheet. | ||
* @returns {Function} | ||
*/ | ||
axe.utils.getStyleSheetFactory = function getStyleSheetFactory(dynamicDoc) { | ||
if (!dynamicDoc) { | ||
throw new Error( | ||
'axe.utils.getStyleSheetFactory should be invoked with an argument' | ||
); | ||
} | ||
|
||
return options => { | ||
const { | ||
data, | ||
isCrossOrigin = false, | ||
shadowId, | ||
root, | ||
priority, | ||
isLink = false | ||
} = options; | ||
const style = dynamicDoc.createElement('style'); | ||
if (isLink) { | ||
// as creating a stylesheet as link will need to be awaited | ||
// till `onload`, it is wise to convert link href to @import statement | ||
const text = dynamicDoc.createTextNode(`@import "${data.href}"`); | ||
style.appendChild(text); | ||
} else { | ||
style.appendChild(dynamicDoc.createTextNode(data)); | ||
} | ||
dynamicDoc.head.appendChild(style); | ||
return { | ||
sheet: style.sheet, | ||
isCrossOrigin, | ||
shadowId, | ||
root, | ||
priority | ||
}; | ||
}; | ||
}; |
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,53 @@ | ||
/** | ||
* Parse cross-origin stylesheets | ||
* | ||
* @method parseCrossOriginStylesheet | ||
* @memberof axe.utils | ||
* @param {String} url url from which to fetch stylesheet | ||
* @param {Object} options options object from `axe.utils.parseStylesheet` | ||
* @param {Array<Number>} priority sheet priority | ||
* @param {Array<String>} importedUrls urls of already imported stylesheets | ||
* @param {Boolean} isCrossOrigin boolean denoting if a stylesheet is `cross-origin` | ||
* @returns {Promise} | ||
*/ | ||
axe.utils.parseCrossOriginStylesheet = function parseCrossOriginStylesheet( | ||
url, | ||
options, | ||
priority, | ||
importedUrls, | ||
isCrossOrigin | ||
) { | ||
const axiosOptions = { | ||
method: 'get', | ||
url | ||
}; | ||
|
||
/** | ||
* Add `url` to `importedUrls` | ||
*/ | ||
importedUrls.push(url); | ||
|
||
/** | ||
* Fetch `cross-origin stylesheet` via axios | ||
*/ | ||
return axe.imports.axios(axiosOptions).then(({ data }) => { | ||
const result = options.convertDataToStylesheet({ | ||
data, | ||
isCrossOrigin, | ||
priority, | ||
root: options.rootNode, | ||
shadowId: options.shadowId | ||
}); | ||
|
||
/** | ||
* Parse resolved stylesheet further for any `@import` styles | ||
*/ | ||
return axe.utils.parseStylesheet( | ||
result.sheet, | ||
options, | ||
priority, | ||
importedUrls, | ||
result.isCrossOrigin | ||
); | ||
}); | ||
}; |
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,96 @@ | ||
/** | ||
* Parse non cross-origin stylesheets | ||
* | ||
* @method parseSameOriginStylesheet | ||
* @memberof axe.utils | ||
* @param {Object} sheet CSSStylesheet object | ||
* @param {Object} options options object from `axe.utils.parseStylesheet` | ||
* @param {Array<Number>} priority sheet priority | ||
* @param {Array<String>} importedUrls urls of already imported stylesheets | ||
* @param {Boolean} isCrossOrigin boolean denoting if a stylesheet is `cross-origin` | ||
* @returns {Promise} | ||
*/ | ||
axe.utils.parseSameOriginStylesheet = function parseSameOriginStylesheet( | ||
sheet, | ||
options, | ||
priority, | ||
importedUrls, | ||
isCrossOrigin = false | ||
) { | ||
const rules = Array.from(sheet.cssRules); | ||
|
||
if (!rules) { | ||
return Promise.resolve(); | ||
} | ||
|
||
/** | ||
* reference -> https://developer.mozilla.org/en-US/docs/Web/API/CSSRule#Type_constants | ||
*/ | ||
const cssImportRules = rules.filter(r => r.type === 3); // type === 3 -> CSSRule.IMPORT_RULE | ||
|
||
/** | ||
* when no `@import` rules in given sheet -> resolve the current `sheet` & exit | ||
*/ | ||
if (!cssImportRules.length) { | ||
// exit | ||
return Promise.resolve({ | ||
isCrossOrigin, | ||
priority, | ||
root: options.rootNode, | ||
shadowId: options.shadowId, | ||
sheet | ||
}); | ||
} | ||
|
||
/** | ||
* filter rules that are not already fetched | ||
*/ | ||
const cssImportUrlsNotAlreadyImported = cssImportRules | ||
// ensure rule has a href | ||
.filter(rule => rule.href) | ||
// extract href from object | ||
.map(rule => rule.href) | ||
// only href that are not already imported | ||
.filter(url => !importedUrls.includes(url)); | ||
|
||
/** | ||
* iterate `@import` rules and fetch styles | ||
*/ | ||
const promises = cssImportUrlsNotAlreadyImported.map( | ||
(importUrl, cssRuleIndex) => { | ||
const newPriority = [...priority, cssRuleIndex]; | ||
const isCrossOriginRequest = /^https?:\/\/|^\/\//i.test(importUrl); | ||
|
||
return axe.utils.parseCrossOriginStylesheet( | ||
importUrl, | ||
options, | ||
newPriority, | ||
importedUrls, | ||
isCrossOriginRequest | ||
); | ||
} | ||
); | ||
|
||
const nonImportCSSRules = rules.filter(r => r.type !== 3); | ||
|
||
// no further rules to process in this sheet | ||
if (!nonImportCSSRules.length) { | ||
return Promise.all(promises); | ||
} | ||
|
||
// convert all `nonImportCSSRules` style rules into `text` and chain | ||
|
||
promises.push( | ||
Promise.resolve( | ||
options.convertDataToStylesheet({ | ||
data: nonImportCSSRules.map(rule => rule.cssText).join(), | ||
isCrossOrigin, | ||
priority, | ||
root: options.rootNode, | ||
shadowId: options.shadowId | ||
}) | ||
) | ||
); | ||
|
||
return Promise.all(promises); | ||
}; |
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,70 @@ | ||
/** | ||
* Parse a given stylesheet | ||
* | ||
* @method parseStylesheet | ||
* @memberof axe.utils | ||
* @param {Object} sheet stylesheet to parse | ||
* @param {Object} options configuration options object from `axe.utils.parseStylesheets` | ||
* @param {Array<Number>} priority priority of stylesheet | ||
* @param {Array<String>} importedUrls list of resolved `@import` urls | ||
* @param {Boolean} isCrossOrigin boolean denoting if a stylesheet is `cross-origin`, passed for re-parsing `cross-origin` sheets | ||
* @returns {Promise} | ||
*/ | ||
axe.utils.parseStylesheet = function parseStylesheet( | ||
sheet, | ||
options, | ||
priority, | ||
importedUrls, | ||
isCrossOrigin = false | ||
) { | ||
const isSameOrigin = isSameOriginStylesheet(sheet); | ||
if (isSameOrigin) { | ||
/** | ||
* resolve `same-origin` stylesheet | ||
*/ | ||
return axe.utils.parseSameOriginStylesheet( | ||
sheet, | ||
options, | ||
priority, | ||
importedUrls, | ||
isCrossOrigin | ||
); | ||
} | ||
|
||
/** | ||
* resolve `cross-origin` stylesheet | ||
*/ | ||
return axe.utils.parseCrossOriginStylesheet( | ||
sheet.href, | ||
options, | ||
priority, | ||
importedUrls, | ||
true // -> isCrossOrigin | ||
); | ||
}; | ||
|
||
/** | ||
* Check if a given stylesheet is from the `same-origin` | ||
* Note: | ||
* `sheet.cssRules` throws an error on `cross-origin` stylesheets | ||
* | ||
* @param {Object} sheet CSS stylesheet | ||
* @returns {Boolean} | ||
*/ | ||
function isSameOriginStylesheet(sheet) { | ||
try { | ||
/*eslint no-unused-vars: 0*/ | ||
const rules = sheet.cssRules; | ||
|
||
/** | ||
* Safari, does not throw an error when accessing cssRules property, | ||
*/ | ||
if (!rules && sheet.href) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} catch (e) { | ||
return false; | ||
} | ||
} |
Oops, something went wrong.