-
Notifications
You must be signed in to change notification settings - Fork 513
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(build): split up document-extractor
- Loading branch information
Showing
8 changed files
with
834 additions
and
842 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
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,143 @@ | ||
import * as bcd from "@mdn/browser-compat-data/types"; | ||
import { packageBCD } from "./resolve-bcd"; | ||
|
||
interface SimpleSupportStatementWithReleaseDate | ||
extends bcd.SimpleSupportStatement { | ||
release_date?: string; | ||
} | ||
|
||
export function extractBCD(query: string): { | ||
browsers: bcd.Browsers | null; | ||
data: bcd.Identifier | null; | ||
} { | ||
const { browsers, data }: { browsers: bcd.Browsers; data: bcd.Identifier } = | ||
packageBCD(query); | ||
|
||
if (data === undefined) { | ||
return { browsers: null, data: null }; | ||
} | ||
|
||
// First extract a map of all release data, keyed by (normalized) browser | ||
// name and the versions. | ||
// You'll have a map that looks like this: | ||
// | ||
// 'chrome_android': { | ||
// '28': { | ||
// release_date: '2012-06-01', | ||
// release_notes: '...', | ||
// ... | ||
// | ||
// The reason we extract this to a locally scoped map, is so we can | ||
// use it to augment the `__compat` blocks for the latest version | ||
// when (if known) it was added. | ||
const browserReleaseData = new Map(); | ||
for (const [name, browser] of Object.entries(browsers)) { | ||
const releaseData = new Map(); | ||
for (const [version, data] of Object.entries(browser.releases || [])) { | ||
if (data) { | ||
releaseData.set(version, data); | ||
} | ||
} | ||
browserReleaseData.set(name, releaseData); | ||
} | ||
|
||
for (const block of _extractCompatBlocks(data)) { | ||
for (const [browser, originalInfo] of Object.entries(block.support)) { | ||
// `originalInfo` here will be one of the following: | ||
// - a single simple_support_statement: | ||
// { version_added: 42 } | ||
// - an array of simple_support_statements: | ||
// [ { version_added: 42 }, { prefix: '-moz', version_added: 35 } ] | ||
// | ||
// Standardize the first version to an array of one, so we don't have | ||
// to deal with two different forms below | ||
|
||
const infos: SimpleSupportStatementWithReleaseDate[] = Array.isArray( | ||
originalInfo | ||
) | ||
? originalInfo | ||
: [originalInfo]; | ||
|
||
for (const infoEntry of infos) { | ||
const added = | ||
typeof infoEntry.version_added === "string" && | ||
infoEntry.version_added.startsWith("≤") | ||
? infoEntry.version_added.slice(1) | ||
: infoEntry.version_added; | ||
if (browserReleaseData.has(browser)) { | ||
if (browserReleaseData.get(browser).has(added)) { | ||
infoEntry.release_date = browserReleaseData | ||
.get(browser) | ||
.get(added).release_date; | ||
} | ||
} | ||
} | ||
|
||
infos.sort((a, b) => | ||
_compareVersions(_getFirstVersion(b), _getFirstVersion(a)) | ||
); | ||
|
||
block.support[browser] = infos; | ||
} | ||
} | ||
|
||
return { | ||
data, | ||
browsers, | ||
}; | ||
} | ||
|
||
function _getFirstVersion(support: bcd.SimpleSupportStatement): string { | ||
if (typeof support.version_added === "string") { | ||
return support.version_added; | ||
} else if (typeof support.version_removed === "string") { | ||
return support.version_removed; | ||
} else { | ||
return "0"; | ||
} | ||
} | ||
|
||
function _compareVersions(a: string, b: string) { | ||
const x = _splitVersion(a); | ||
const y = _splitVersion(b); | ||
|
||
return _compareNumberArray(x, y); | ||
} | ||
|
||
function _compareNumberArray(a: number[], b: number[]): number { | ||
while (a.length || b.length) { | ||
const x = a.shift() || 0; | ||
const y = b.shift() || 0; | ||
if (x !== y) { | ||
return x - y; | ||
} | ||
} | ||
|
||
return 0; | ||
} | ||
function _splitVersion(version: string): number[] { | ||
if (version.startsWith("≤")) { | ||
version = version.slice(1); | ||
} | ||
|
||
return version.split(".").map(Number); | ||
} | ||
|
||
/** | ||
* Recursively extracts `__compat` objects from the `feature` and from all | ||
* nested features at any depth. | ||
* | ||
* @param {bcd.Identifier} feature The feature. | ||
* @returns {bcd.CompatStatement[]} The array of `__compat` objects. | ||
*/ | ||
function _extractCompatBlocks(feature: bcd.Identifier): bcd.CompatStatement[] { | ||
const blocks: bcd.CompatStatement[] = []; | ||
for (const [key, value] of Object.entries(feature)) { | ||
if (key === "__compat") { | ||
blocks.push(value as bcd.CompatStatement); | ||
} else if (typeof value === "object") { | ||
blocks.push(..._extractCompatBlocks(value as bcd.Identifier)); | ||
} | ||
} | ||
return blocks; | ||
} |
Oops, something went wrong.