Namespaces
Variants
Actions

User:D41D8CD98F/append-support-info.js

From cppreference.com

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Clear the cache in Tools → Preferences
if (mw && mw.config.get('wgNamespaceNumber') === 0)
(function() {
const HEADLINE_TEXT = 'Support status';
const NOTE_TEMPLATE =
    '<small>The support data are automatically generated from $0. Some rows might be inapplicable to this page.</small>';
const CXX_SUPPORT_LINK = '<a href="/w/cpp/compiler_support" title="cpp/compiler support">C++ compiler support</a>';
const C_SUPPORT_LINK = '<a href="/w/c/compiler_support" title="c/compiler support">C compiler support</a>';
const MISSING_CELL =
    '<td style="background:#ececec;color:grey;vertical-align:middle;text-align:center;" class="table-na">' +
    '<small>N/A</small></td>';
const TABLE_HEAD_TEXT = 'Feature\n\xA0';
 
async function fetch_pages(pagenames) {
    const params = new URLSearchParams({
        format: 'json',
        action: 'query',
        prop: 'revisions',
        rvprop: 'content',
        rvparse: true,
        titles: pagenames.join('|'),
    });
    const apiresult = await fetch('/mwiki/api.php?' + params.toString()).then(r => r.json());
    return Object.values(apiresult.query.pages);
}
 
function get_revision_marker_in_page() {
    const marker = document.querySelector('#firstHeading > .t-mark-rev');
    if (marker !== null) {
        return [new Set(marker.classList)];
    }
    const dcl = Array.from(document.querySelectorAll('.t-dcl-begin:not(h3 ~ *, .t-member *)'));
    const elems = dcl.flatMap(elem => Array.from(elem.querySelectorAll('.t-dcl-rev-notes, .t-dcl:not(.t-dcl-rev-notes *)')));
    return elems.map(elem => new Set(elem.classList));
}
 
function guess_relevant_revs(lang, revs) {
    const markers_class_sets = get_revision_marker_in_page();
 
    if (markers_class_sets.length === 0) {
        return revs;
    }
 
    let since = revs.length, until = 0;
    for (const class_set of markers_class_sets) {
        let has_since = false;
        let has_until = false;
        for (const [i, rev] of revs.entries()) {
            if (class_set.has(`t-since-${lang}${rev}`)) {
                has_since = true;
                since = Math.min(since, i);
            }
            if (class_set.has(`t-until-${lang}${rev}`)) {
                has_until = true;
                until = Math.max(until, i);
            }
        }
        since = has_since ? since : 0;
        until = has_until ? until : revs.length;
    }
 
    return revs.slice(since, until + 1);
}
 
function convert_table_to_array(table) {
    const result = [];
    let row_index = 0;
    for (const row of table.rows) {
        if (!result[row_index]) {
            result[row_index] = [];
        }
        let cell_index = 0;
        for (const cell of row.cells) {
            while (result[row_index][cell_index]) {
                ++cell_index;
            }
            for (let i = 0; i < cell.rowSpan; ++i) {
                if (!result[row_index + i]) {
                    result[row_index + i] = [];
                }
                result[row_index + i][cell_index] = cell;
            }
        }
        ++row_index;
    }
    return result;
}
 
function process_feature_test_macro_table(table) {
    const arr = convert_table_to_array(table).slice(1);
    if (table.matches('.ftm-has-value')) {
        return arr.map(row => ({name: row[0].textContent.trim(), value: row[1].textContent.trim()}));
    } else {
        return arr.map(row => ({name: row[0].textContent.trim(), value: undefined}));
    }
}
 
function get_paper_numbers_in_row(row) {
    return Array.from(row.at(-1).querySelectorAll('.external')).map(link => link.text);
}
 
async function guess_relevant_papers_from_feature_test_macros() {
    const ftm_tables = Array.from(document.querySelectorAll('.ftm-begin'));
    const macros = ftm_tables.flatMap(table => process_feature_test_macro_table(table));
 
    if (macros.length === 0) {
        return [];
    }
 
    const ftm_page = await fetch_pages(['cpp/feature test']);
    const ftm_page_content = new DOMParser().parseFromString(ftm_page[0].revisions[0]['*'], 'text/html');
    const data_tables = Array.from(ftm_page_content.querySelectorAll('.wikitable'));
    const data_rows = data_tables.flatMap(table => convert_table_to_array(table).slice(1, -1));
 
    const relevant_rows = [];
    for (const row of data_rows) {
        const name = row[0].textContent.trim();
        const value = row[2].textContent.trim();
        for (const macro of macros) {
            if (macro.name === name && (!macro.value || macro.value === value)) {
                relevant_rows.push(row);
            }
        }
    }
 
    return relevant_rows.flatMap(row => get_paper_numbers_in_row(row));
}
 
function is_relevant_row(row, relevant_papers) {
    const links = Array.from(row.querySelectorAll('a'));
    if (links.some(a => `${document.URL}/`.startsWith(`${a.href}/`))) {
        return true;
    }
    const header = document.querySelector('.t-dcl-begin .t-dsc-header a');
    if (header && links.some(a => a.href === header.href)) {
        return true;
    }
    const papers = Array.from(row.querySelectorAll('.external'));
    if (papers.some(paper => relevant_papers.includes(paper.text))) {
        return true;
    }
    return false;
}
 
function get_relevant_rows(content, selector, papers) {
    const table = content.querySelector(selector);
    if (!table) {
        return {body: []};
    }
    const rows = Array.from(table.querySelectorAll('tr'));
    const relevant_rows = rows.slice(1, -1).filter(row => is_relevant_row(row, papers));
    return {head: rows[0], body: relevant_rows};
}
 
function get_relevant_data(content, papers) {
    return {
        compiler_support: get_relevant_rows(content, '.t-compiler-support-top', papers),
        library_support: get_relevant_rows(content, '.t-standard-library-support-top', papers),
    };
}
 
function are_matching_cells(cell1, cell2) {
    return cell1.textContent.trim() === cell2.textContent.trim();
}
 
function fixup_missing_columns(dst_data, src_data) {
    const dst_head_cells = Array.from(dst_data.head.cells);
    const src_head_cells = src_data.head.cells;
    for (let i = 1; i < src_head_cells.length; ++i) {
        const src_cell = src_head_cells[i];
        const src_cell_in_dst_head = dst_head_cells.some(dst_cell => are_matching_cells(dst_cell, src_cell));
        if (!src_cell_in_dst_head) {
            dst_data.head.insertBefore(src_cell.cloneNode(true), dst_head_cells[i]);
            for (const row of dst_data.body) {
                const cell = row.insertCell(i);
                cell.outerHTML = MISSING_CELL;
            }
        }
    }
}
 
function merge_support_data(old_data, new_data) {
    if (!new_data.head || new_data.body.length === 0) {
        return;
    } else if (!old_data.head) {
        old_data.head = new_data.head;
        old_data.body = new_data.body;
    } else {
        fixup_missing_columns(old_data, new_data);
        fixup_missing_columns(new_data, old_data);
        old_data.body = old_data.body.concat(new_data.body);
    }
}
 
function append_support_table(current_page_content, data, kind) {
    if (data.body.length !== 0) {
        const table = document.createElement('table');
        table.classList.add('wikitable', 'support-data-begin', `${kind}-support-data-begin`);
        table.style.fontSize = '0.8em';
 
        const tbody = table.createTBody();
        const head = data.head;
        head.cells[0].innerText = TABLE_HEAD_TEXT;
        head.lastElementChild.remove();
        tbody.append(head);
        tbody.append(...data.body);
 
        current_page_content.append(table);
    }
}
 
async function append_support_info(is_cxx, revs) {
    const get_pagename = rev => `Template:${is_cxx ? 'cpp' : 'c'}/compiler support/${rev}`;
 
    const fetch_data_promise = fetch_pages(revs.map(get_pagename));
    const guess_papers_promise = guess_relevant_papers_from_feature_test_macros();
 
    const [pages, relevant_papers] = await Promise.all([fetch_data_promise, guess_papers_promise]);
 
    const relevant_revs = guess_relevant_revs(is_cxx ? 'cxx' : 'c', revs);
    const relevant_pagenames = relevant_revs.map(get_pagename);
 
    const relevant_support_pages = pages.filter(page => relevant_pagenames.includes(page.title));
 
    const compiler_support = {body: []};
    const library_support = {body: []};
 
    for (const page of relevant_support_pages) {
        const content = new DOMParser().parseFromString(page.revisions[0]['*'], 'text/html');
        const data = get_relevant_data(content, relevant_papers);
        merge_support_data(compiler_support, data.compiler_support);
        merge_support_data(library_support, data.library_support);
    }
 
    const current_page_content = document.querySelector('#mw-content-text');
    if (compiler_support.body.length !== 0 || library_support.body.length !== 0) {
        const headline = document.createElement('h3');
        headline.textContent = HEADLINE_TEXT;
        const note = document.createElement('p');
        note.innerHTML = NOTE_TEMPLATE.replace('$0', is_cxx ? CXX_SUPPORT_LINK : C_SUPPORT_LINK);
 
        current_page_content.append(headline);
        current_page_content.append(note);
 
        append_support_table(current_page_content, compiler_support, 'core');
        append_support_table(current_page_content, library_support, 'lib');
    }
}
 
const is_cxx = !document.URL.match(/\bc\//);
const revs = is_cxx ? ['11', '14', '17', '20', '23', '26'] : ['99', '23'];
append_support_info(is_cxx, revs);
})();