Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ packages/core/src/Page/PageConfig.js
packages/core/src/Site/SiteConfig.js
packages/core/src/html/elements.js
packages/core/src/html/Context.js
packages/core/src/html/linkProcessor.js
packages/core/src/html/NodeProcessor.js
packages/core/src/html/scriptAndStyleTagProcessor.js
packages/core/src/html/SiteLinkManager.js
packages/core/src/lib/nunjucks-extensions/index.js
packages/core/src/lib/nunjucks-extensions/nunjucks-date.js
packages/core/src/lib/nunjucks-extensions/set-external.js
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ packages/core/src/Page/PageConfig.js
packages/core/src/Site/SiteConfig.js
packages/core/src/html/elements.js
packages/core/src/html/Context.js
packages/core/src/html/linkProcessor.js
packages/core/src/html/NodeProcessor.js
packages/core/src/html/scriptAndStyleTagProcessor.js
packages/core/src/html/SiteLinkManager.js
packages/core/src/lib/nunjucks-extensions/index.js
packages/core/src/lib/nunjucks-extensions/nunjucks-date.js
packages/core/src/lib/nunjucks-extensions/set-external.js
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/html/NodeProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { shiftSlotNodeDeeper, transformOldSlotSyntax, renameSlot } from './vueSl
import { MdAttributeRenderer } from './MdAttributeRenderer';
import { MarkdownProcessor } from './MarkdownProcessor';
import { processScriptAndStyleTag } from './scriptAndStyleTagProcessor';
import { SiteLinkManager } from './SiteLinkManager';

const fm = require('fastmatter');

Expand Down Expand Up @@ -73,7 +74,7 @@ export class NodeProcessor {
private pageSources: PageSources,
private variableProcessor: VariableProcessor,
private pluginManager: any,
private siteLinkManager: any,
private siteLinkManager: SiteLinkManager,
private userScriptsAndStyles: string[] | undefined,
docId = '',
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
const linkProcessor = require('./linkProcessor');
import has from 'lodash/has';
import { DomElement } from 'htmlparser2';
import * as linkProcessor from './linkProcessor';
import { NodeProcessorConfig } from './NodeProcessor';

const _ = {};
_.has = require('lodash/has');
const _ = { has };

const tagsToValidate = new Set([
const tagsToValidate: Set<string> = new Set([
'img',
'pic',
'thumbnail',
Expand All @@ -12,8 +14,11 @@ const tagsToValidate = new Set([
'script',
]);

class SiteLinkManager {
constructor(config) {
export class SiteLinkManager {
private config: NodeProcessorConfig;
private intralinkCollection: Map<string, Set<string>>;

constructor(config: NodeProcessorConfig) {
this.config = config;
this.intralinkCollection = new Map();
}
Expand All @@ -22,11 +27,12 @@ class SiteLinkManager {
* Adds a resourcePath and cwf to the intralinkCollection,
* ensuring each pair of (resourcePath, cwf) appears only once
*/
_addToCollection(resourcePath, cwf) {
_addToCollection(resourcePath: string, cwf: string) {
if (!this.intralinkCollection.has(cwf)) {
this.intralinkCollection.set(cwf, new Set());
}
this.intralinkCollection.get(cwf).add(resourcePath);
// We have checked and set cwf in intralinkCollection above
this.intralinkCollection.get(cwf)!.add(resourcePath);
}

validateAllIntralinks() {
Expand All @@ -45,8 +51,8 @@ class SiteLinkManager {
* Add a link to the intralinkCollection to be validated later,
* if the node should be validated and intralink validation is not disabled.
*/
collectIntraLinkToValidate(node, cwf) {
if (!tagsToValidate.has(node.name)) {
collectIntraLinkToValidate(node: DomElement, cwf: string) {
if (node.name && !tagsToValidate.has(node.name)) {
return 'Should not validate';
}

Expand All @@ -58,15 +64,11 @@ class SiteLinkManager {
}

const resourcePath = linkProcessor.getDefaultTagsResourcePath(node);
if (!linkProcessor.isIntraLink(resourcePath)) {
if (!resourcePath || !linkProcessor.isIntraLink(resourcePath)) {
return 'Should not validate';
}

this._addToCollection(resourcePath, cwf);
return 'Intralink collected to be validated later';
}
}

module.exports = {
SiteLinkManager,
};
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
const path = require('path');
const lodashHas = require('lodash/has');
const parse = require('url-parse');
const ignore = require('ignore');
import path from 'path';
import has from 'lodash/has';
import parse from 'url-parse';
import ignore from 'ignore';

const fsUtil = require('../utils/fsUtil');
const logger = require('../utils/logger');
const urlUtil = require('../utils/urlUtil');
import { DomElement } from 'htmlparser2';
import * as fsUtil from '../utils/fsUtil';
import * as logger from '../utils/logger';
import * as urlUtil from '../utils/urlUtil';

const { PluginManager } = require('../plugins/PluginManager');
import { PluginManager } from '../plugins/PluginManager';
import { NodeProcessorConfig } from './NodeProcessor';
import { PageSources } from '../Page/PageSources';

const _ = { has };

const pluginTagConfig = PluginManager.tagConfig;

const defaultTagLinkMap = {
const defaultTagLinkMap: { [key: string]: string } = {
img: 'src',
pic: 'src',
thumbnail: 'src',
Expand All @@ -23,34 +28,36 @@ const defaultTagLinkMap = {
script: 'src',
};

function hasTagLink(node) {
return node.name in defaultTagLinkMap || node.name in pluginTagConfig;
export function hasTagLink(node: DomElement) {
return node.name && (node.name in defaultTagLinkMap || node.name in pluginTagConfig);
}

function getDefaultTagsResourcePath(node) {
export function getDefaultTagsResourcePath(node: DomElement): string {
if (!node.name || !node.attribs) return '';
const linkAttribName = defaultTagLinkMap[node.name];
const resourcePath = node.attribs && node.attribs[linkAttribName];
const resourcePath = node.attribs[linkAttribName];
return resourcePath;
}

function getResourcePathFromRoot(rootPath, fullResourcePath) {
function _getResourcePathFromRoot(rootPath: string, fullResourcePath: string) {
return fsUtil.ensurePosix(path.relative(rootPath, fullResourcePath));
}

/**
* @param {string} resourcePath parsed from the node's relevant attribute
* @returns {boolean} whether the resourcePath is a valid intra-site link
*/
function isIntraLink(resourcePath) {
export function isIntraLink(resourcePath: string | undefined): boolean {
const MAILTO_OR_TEL_REGEX = /^(?:mailto:|tel:)/i;
return resourcePath
return !!resourcePath
&& !urlUtil.isUrl(resourcePath)
&& !resourcePath.startsWith('#')
&& !MAILTO_OR_TEL_REGEX.test(resourcePath);
}

function _convertRelativeLink(node, cwf, rootPath, baseUrl, resourcePath, linkAttribName) {
if (!isIntraLink(resourcePath)) {
function _convertRelativeLink(node: DomElement, cwf: string, rootPath: string,
baseUrl: string, resourcePath: string | undefined, linkAttribName: string) {
if (!resourcePath || !isIntraLink(resourcePath)) {
return;
}

Expand All @@ -61,9 +68,11 @@ function _convertRelativeLink(node, cwf, rootPath, baseUrl, resourcePath, linkAt

const cwd = path.dirname(cwf);
const fullResourcePath = path.join(cwd, resourcePath);
const resourcePathFromRoot = getResourcePathFromRoot(rootPath, fullResourcePath);
const resourcePathFromRoot = _getResourcePathFromRoot(rootPath, fullResourcePath);

node.attribs[linkAttribName] = path.posix.join(baseUrl || '/', resourcePathFromRoot);
if (node.attribs) {
node.attribs[linkAttribName] = path.posix.join(baseUrl || '/', resourcePathFromRoot);
}
}

/**
Expand All @@ -73,12 +82,13 @@ function _convertRelativeLink(node, cwf, rootPath, baseUrl, resourcePath, linkAt
*
* TODO allow plugins to tap into this process / extend {@link defaultTagLinkMap}
*
* @param {Object<any, any>} node from the dom traversal
* @param {DomElement} node from the dom traversal
* @param {string} cwf as flagged from {@link NodeProcessor}
* @param {string} rootPath of the root site
* @param {string} baseUrl
*/
function convertRelativeLinks(node, cwf, rootPath, baseUrl) {
export function convertRelativeLinks(node: DomElement, cwf: string, rootPath: string, baseUrl: string) {
if (!node.name) return;
if (node.name in defaultTagLinkMap) {
const resourcePath = getDefaultTagsResourcePath(node);
const linkAttribName = defaultTagLinkMap[node.name];
Expand All @@ -87,17 +97,17 @@ function convertRelativeLinks(node, cwf, rootPath, baseUrl) {

if (node.name in pluginTagConfig && pluginTagConfig[node.name].attributes && node.attribs) {
pluginTagConfig[node.name].attributes.forEach((attrConfig) => {
if (attrConfig.isRelative) {
if (attrConfig.isRelative && node.attribs) {
const resourcePath = node.attribs[attrConfig.name];
_convertRelativeLink(node, cwf, rootPath, baseUrl, resourcePath, attrConfig.name);
}
});
}
}

function convertMdExtToHtmlExt(node) {
export function convertMdExtToHtmlExt(node: DomElement) {
if (node.name === 'a' && node.attribs && node.attribs.href) {
const hasNoConvert = lodashHas(node.attribs, 'no-convert');
const hasNoConvert = _.has(node.attribs, 'no-convert');
if (hasNoConvert) {
return;
}
Expand Down Expand Up @@ -129,7 +139,7 @@ function convertMdExtToHtmlExt(node) {
}
}

function isValidPageSource(resourcePath, config) {
function isValidPageSource(resourcePath: string, config: NodeProcessorConfig) {
const relativeResourcePath = resourcePath.startsWith('/')
? resourcePath.substring(1)
: resourcePath;
Expand All @@ -138,7 +148,7 @@ function isValidPageSource(resourcePath, config) {
return isPageSrc;
}

function isValidFileAsset(resourcePath, config) {
function isValidFileAsset(resourcePath: string, config: NodeProcessorConfig) {
const relativeResourcePath = resourcePath.startsWith('/')
? resourcePath.substring(1)
: resourcePath;
Expand All @@ -156,10 +166,10 @@ function isValidFileAsset(resourcePath, config) {
*
* @param {string} resourcePath parsed from the node's relevant attribute
* @param {string} cwf as flagged from {@link NodePreprocessor}
* @param {Object<any, any>} config passed for page metadata access
* @param {NodeProcessorConfig} config passed for page metadata access
* @returns {string} these string return values are for unit testing purposes only
*/
function validateIntraLink(resourcePath, cwf, config) {
export function validateIntraLink(resourcePath: string, cwf: string, config: NodeProcessorConfig): string {
if (!isIntraLink(resourcePath)) {
return 'Not Intralink';
}
Expand Down Expand Up @@ -220,20 +230,22 @@ function validateIntraLink(resourcePath, cwf, config) {
* Resolves and collects source file paths pointed to by attributes in nodes for live reload.
* Only necessary for plugins for now.
*
* @param {Object<any, any>} node from the dom traversal
* @param {DomElement} node from the dom traversal
* @param {string} rootPath site root path to resolve the link from
* @param {string} baseUrl base url to strip off the link (if any)
* @param {PageSources} pageSources {@link PageSources} object to add the resolved file path to
* @returns {string} these string return values are for unit testing purposes only
* @returns {string | void} these string return values are for unit testing purposes only
*/
function collectSource(node, rootPath, baseUrl, pageSources) {
export function collectSource(node: DomElement, rootPath: string,
baseUrl: string, pageSources: PageSources): string | void {
if (!node.name) return;
const tagConfig = pluginTagConfig[node.name];
if (!tagConfig || !tagConfig.attributes) {
return;
}

tagConfig.attributes.forEach((attrConfig) => {
if (!attrConfig.isSourceFile) {
if (!attrConfig.isSourceFile || !node.attribs) {
return;
}

Expand All @@ -251,13 +263,3 @@ function collectSource(node, rootPath, baseUrl, pageSources) {
pageSources.staticIncludeSrc.push({ to: fullResourcePath });
});
}

module.exports = {
getDefaultTagsResourcePath,
hasTagLink,
convertRelativeLinks,
convertMdExtToHtmlExt,
validateIntraLink,
collectSource,
isIntraLink,
};