blob: c4eab122be4d01189cb4bbbc68255ac82d7da866 [file] [log] [blame] [edit]
/* This file is a part of @mdn/browser-compat-data
* See LICENSE file for more information. */
import {
CompatData,
CompatStatement,
Identifier,
BrowserStatement,
ReleaseStatement,
} from '../types/types.js';
import { DataType } from '../types/index.js';
import bcd from '../index.js';
import { isBrowser, descendantKeys, joinPath } from './walkingUtils.js';
import query from './query.js';
interface BrowserReleaseWalkOutput {
path: string;
data: DataType;
browser: BrowserStatement;
browserRelease: ReleaseStatement;
}
interface LowLevelWalkOutput {
path: string;
data: DataType;
browser?: BrowserStatement;
compat?: CompatStatement;
browserRelease?: ReleaseStatement;
}
export interface WalkOutput {
path: string;
data: DataType;
compat: CompatStatement;
}
/**
* Walk through the browser releases
* @param data The data to iterate
* @param path The current path
* @yields {BrowserReleaseWalkOutput} The release info
*/
export function* browserReleaseWalk(
data: DataType,
path?: string,
): IterableIterator<BrowserReleaseWalkOutput> {
for (const [release, releaseData] of Object.entries(data.releases)) {
yield {
path: joinPath(path, 'releases', release),
data,
browser: data,
browserRelease: releaseData as ReleaseStatement,
};
}
}
/**
* Walk through the compatibility statements
* @param data The data to iterate
* @param path The current path
* @param depth The maximum depth to iterate
* @yields {LowLevelWalkOutput} The feature info
*/
export function* lowLevelWalk(
data: DataType = bcd,
path?: string,
depth = Infinity,
): IterableIterator<LowLevelWalkOutput> {
if (path !== undefined && path !== '__meta') {
const next: LowLevelWalkOutput = {
path,
data,
};
if (isBrowser(data)) {
next.browser = data;
yield next;
yield* browserReleaseWalk(data, path);
} else {
if (data.__compat !== undefined) {
next.compat = data.__compat;
}
yield next;
}
}
if (depth > 0) {
for (const key of descendantKeys(data)) {
yield* lowLevelWalk(data[key], joinPath(path, key), depth - 1);
}
}
}
/**
* Walk the data for compat features
* @param entryPoints Entry points to iterate
* @param data The data to iterate
* @yields {WalkOutput} The feature info
*/
export default function* walk(
entryPoints?: string | string[],
data: CompatData | CompatStatement | Identifier = bcd,
): IterableIterator<WalkOutput> {
const walkers: IterableIterator<LowLevelWalkOutput>[] = [];
if (entryPoints === undefined) {
walkers.push(lowLevelWalk(data));
} else {
entryPoints = Array.isArray(entryPoints) ? entryPoints : [entryPoints];
walkers.push(
...entryPoints.map((entryPoint) =>
lowLevelWalk(query(entryPoint, data), entryPoint),
),
);
}
for (const walker of walkers) {
for (const step of walker) {
if (step.compat) {
yield step as WalkOutput;
}
}
}
}