'use strict';
const assert = require('assert-plus');
const cheerio = require('cheerio');
const Encoder = require('node-html-encoder').Encoder;
const fs = require('fs-extra');
const path = require('canonical-path');
module.exports = function dabFactory(ngIoProjPath) {
const encoder = new Encoder('entity');
// Get the functionality we need from the dgeni package by the same name.
const dartApiBuilderDgeniProjPath = 'tools/api-builder/dart-package';
const dab = require(path.resolve(ngIoProjPath, dartApiBuilderDgeniProjPath)).module;
const log = dab.logFactory[1]();
const dartPkgConfigInfo = dab.dartPkgConfigInfo[1]();
const preprocessDartDocData = dab.preprocessDartDocData[1](log, dartPkgConfigInfo);
const loadDartDocDataProcessor = dab.loadDartDocDataProcessor[1](log, dartPkgConfigInfo, preprocessDartDocData);
const apiListDataFileService = dab.apiListDataFileService[1](log, dartPkgConfigInfo);
const Array_from = dab.arrayFromIterable[1];
// Load API data, then create and save 'api-list.json'.
function loadApiDataAndSaveToApiListFile() {
const docs = [];
loadDartDocDataProcessor.$process(docs);
log.debug('Number of Dart API entries loaded:', docs.length);
var libMap = apiListDataFileService.createDataAndSaveToFile(docs);
for (let name in libMap) {
log.debug(' ', name, 'has', libMap[name].length, 'top-level entries');
}
return docs;
}
// Create and save the container's '_data.json' file.
function _createDirData(containerName, destDirPath, entries) {
const entryNames = Array_from(entries.keys()).sort();
const dataMap = Object.create(null);
entryNames.map((n) => {
const e = entries.get(n);
assert.object(e, `entry named ${n}`);
dataMap[path.basename(e.path, '.html')] = e;
});
const dataFilePath = path.resolve(destDirPath, '_data.json');
fs.writeFile(dataFilePath, JSON.stringify(dataMap, null, 2));
log.info(containerName, 'wrote', Object.keys(dataMap).length, 'entries to', dataFilePath);
}
function _adjustDocsRelativeLinks($, div) {
// Omit leading https://angular.io so links work for local test sites.
const urlToDocs = '/docs/dart/latest/';
const urlToExamples = 'http://angular-examples.github.io/';
const docsLinkList = div.find('a[href^="docs/"],a[href^="examples/"]');
docsLinkList.each((i, elt) => {
const href = $(elt).attr('href');
const matches = href.match(/(\w+)\/(.*)$/);
// TODO: support links to chapters of other languages, e.g., 'docs/ts/latest/...'.
const urlStart = matches[1] === 'docs' ? urlToDocs : urlToExamples;
const absHref = urlStart + matches[2];
log.info(`Found angular.io relative link: ${href} --> ${absHref}`);
$(elt).attr('href', absHref);
});
}
function _insertExampleFragments(enclosedByName, eltId, $, div) {
const fragDirBase = path.join(dartPkgConfigInfo.ngIoDartApiDocPath, '../../../_fragments/');
const exList = div.find('p:contains("{@example")');
exList.each((i, elt) => {
const text = $(elt).text();
log.debug(`Found example: ${enclosedByName} ${eltId}`, text);
const matches = text.match(/^\s*{@example\s+([^\s]+)(\s+region=[\'\"]?([-\w]+)[\'\"]?)?\s*}([\s\S]*)$/);
if (!matches) {
log.warn(enclosedByName, eltId, 'has an invalidly formed @example tag:', text);
return true;
}
// const [, exRelPath, /*regionTagAndValue*/, region, rest] = matches;
const rest = matches[4].trim();
if (rest) log.warn(enclosedByName, eltId, '@example must be the only element in a paragraph, but found:', text);
const exRelPath = matches[1];
const region = matches[3];
let exRelPathParts = path.dirname(exRelPath).split(path.sep);
let fragDir;
if (exRelPathParts[0] === 'docs') {
// Path is to a docs example, not an API example.
const exampleName = exRelPathParts[1];
fragDir = path.join(fragDirBase, exampleName, 'dart');
exRelPathParts = exRelPathParts.slice(2);
} else {
fragDir = path.join(fragDirBase, '_api');
}
const extn = path.extname(exRelPath);
const baseName = path.basename(exRelPath, extn);
const fileNameNoExt = baseName + (region ? `-${region}` : '')
const exFragPath = path.resolve(fragDir, ...exRelPathParts, `${fileNameNoExt}${extn}.md`);
if (!fs.existsSync(exFragPath)) {
log.warn('Fragment not found:', exFragPath);
return true;
}
$(elt).empty();
const md = fs.readFileSync(exFragPath, 'utf8');
const codeElt = _extractAndWrapInCodeTags(md);
$(elt).html(codeElt);
log.silly('Fragment code in html:', $(elt).html());
});
}
function _extractAndWrapInCodeTags(md) {
const lines = md.split('\n');
// Drop first and last lines that are the code markdown tripple ticks (and last \n):
lines.shift();
while (lines && lines.pop().trim() !== '```') {}
const code = lines.map((line) => encoder.htmlEncode(line)).join('\n');
// TS uses format="linenums"; removing that for now.
return `