Skip to content

Commit e521f97

Browse files
authored
Allow changing parameter properties (MarkBind#1075)
1 parent 4ea52c2 commit e521f97

File tree

3 files changed

+180
-201
lines changed

3 files changed

+180
-201
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ module.exports = {
2929
"lodash/prefer-lodash-method": [0],
3030
"lodash/prefer-noop": [0],
3131
"max-len": ["error", { "code": 110 }],
32+
"no-param-reassign": ["error", { "props": false }],
3233
"operator-linebreak": ["error", "before"],
3334
// override airbnb-base dev dependencies, latest version does not white list __mocks__
3435
"import/no-extraneous-dependencies": [

src/lib/markbind/src/parser.js

Lines changed: 67 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -126,22 +126,22 @@ class Parser {
126126
return _.clone(this.missingIncludeSrc);
127127
}
128128

129-
_renderIncludeFile(filePath, element, context, config, asIfAt = filePath) {
129+
_renderIncludeFile(filePath, node, context, config, asIfAt = filePath) {
130130
try {
131131
this._fileCache[filePath] = this._fileCache[filePath]
132132
? this._fileCache[filePath] : fs.readFileSync(filePath, 'utf8');
133133
} catch (e) {
134134
// Read file fail
135-
const missingReferenceErrorMessage = `Missing reference in: ${element.attribs[ATTRIB_CWF]}`;
135+
const missingReferenceErrorMessage = `Missing reference in: ${node.attribs[ATTRIB_CWF]}`;
136136
e.message += `\n${missingReferenceErrorMessage}`;
137137
this._onError(e);
138-
return utils.createErrorNode(element, e);
138+
return utils.createErrorNode(node, e);
139139
}
140140
const fileContent = this._fileCache[filePath]; // cache the file contents to save some I/O
141141
const { parent, relative } = urlUtils.calculateNewBaseUrls(asIfAt, config.rootPath, config.baseUrlMap);
142142
const userDefinedVariables = config.userDefinedVariablesMap[path.resolve(parent, relative)];
143143
// Extract included variables from the PARENT file
144-
const includeVariables = Parser.extractIncludeVariables(element, context.variables);
144+
const includeVariables = Parser.extractIncludeVariables(node, context.variables);
145145
// Extract page variables from the CHILD file
146146
const pageVariables
147147
= this.extractPageVariables(asIfAt, fileContent, userDefinedVariables, includeVariables);
@@ -162,22 +162,22 @@ class Parser {
162162
});
163163
const aliases = new Map();
164164
Parser.FILE_ALIASES.set(cwf, aliases);
165-
$('import[from]').each((index, element) => {
166-
const filePath = path.resolve(path.dirname(cwf), element.attribs.from);
167-
const variableNames = Object.keys(element.attribs)
165+
$('import[from]').each((index, node) => {
166+
const filePath = path.resolve(path.dirname(cwf), node.attribs.from);
167+
const variableNames = Object.keys(node.attribs)
168168
.filter(name => name !== 'from' && name !== 'as');
169169
// If no namespace is provided, we use the smallest name as one
170170
const largestName = variableNames.sort()[0];
171171
// ... and prepend it with $__MARKBIND__ to reduce collisions.
172172
const generatedAlias = IMPORTED_VARIABLE_PREFIX + largestName;
173-
const alias = _.hasIn(element.attribs, 'as')
174-
? element.attribs.as
173+
const alias = _.hasIn(node.attribs, 'as')
174+
? node.attribs.as
175175
: generatedAlias;
176176
aliases.set(alias, filePath);
177177
this.staticIncludeSrc.push({ from: context.cwf, to: filePath });
178178
// Render inner file content
179179
const { content: renderedContent, childContext, userDefinedVariables }
180-
= this._renderIncludeFile(filePath, element, context, config);
180+
= this._renderIncludeFile(filePath, node, context, config);
181181
this.extractInnerVariablesIfNotProcessed(renderedContent, childContext, config, filePath);
182182
const innerVariables = this.getImportedVariableMap(filePath);
183183
Parser.VARIABLE_LOOKUP.get(filePath).forEach((value, variableName, map) => {
@@ -194,17 +194,23 @@ class Parser {
194194
}
195195

196196
processDynamicResources(context, html) {
197-
const self = this;
198197
const $ = cheerio.load(html, {
199198
xmlMode: false,
200199
decodeEntities: false,
201200
});
201+
202+
const { rootPath } = this;
203+
function getAbsoluteResourcePath(elem, relativeResourcePath) {
204+
const firstParent = elem.closest('div[data-included-from], span[data-included-from]');
205+
const originalSrc = utils.ensurePosix(firstParent.attr('data-included-from') || context);
206+
const originalSrcFolder = path.posix.dirname(originalSrc);
207+
const fullResourcePath = path.posix.join(originalSrcFolder, relativeResourcePath);
208+
const resolvedResourcePath = path.posix.relative(utils.ensurePosix(rootPath), fullResourcePath);
209+
return path.posix.join('{{hostBaseUrl}}', resolvedResourcePath);
210+
}
211+
202212
$('img, pic, thumbnail').each(function () {
203213
const elem = $(this);
204-
if (elem[0].name === 'thumbnail' && elem.attr('src') === undefined) {
205-
// Thumbnail tag without src
206-
return;
207-
}
208214
const resourcePath = utils.ensurePosix(elem.attr('src'));
209215
if (resourcePath === undefined || resourcePath === '') {
210216
// Found empty img/pic resource in resourcePath
@@ -214,12 +220,7 @@ class Parser {
214220
// Do not rewrite.
215221
return;
216222
}
217-
const firstParent = elem.closest('div[data-included-from], span[data-included-from]');
218-
const originalSrc = utils.ensurePosix(firstParent.attr('data-included-from') || context);
219-
const originalSrcFolder = path.posix.dirname(originalSrc);
220-
const fullResourcePath = path.posix.join(originalSrcFolder, resourcePath);
221-
const resolvedResourcePath = path.posix.relative(utils.ensurePosix(self.rootPath), fullResourcePath);
222-
const absoluteResourcePath = path.posix.join('{{hostBaseUrl}}', resolvedResourcePath);
223+
const absoluteResourcePath = getAbsoluteResourcePath(elem, resourcePath);
223224
$(this).attr('src', absoluteResourcePath);
224225
});
225226
$('a, link').each(function () {
@@ -233,12 +234,7 @@ class Parser {
233234
// Do not rewrite.
234235
return;
235236
}
236-
const firstParent = elem.closest('div[data-included-from], span[data-included-from]');
237-
const originalSrc = utils.ensurePosix(firstParent.attr('data-included-from') || context);
238-
const originalSrcFolder = path.posix.dirname(originalSrc);
239-
const fullResourcePath = path.posix.join(originalSrcFolder, resourcePath);
240-
const resolvedResourcePath = path.posix.relative(utils.ensurePosix(self.rootPath), fullResourcePath);
241-
const absoluteResourcePath = path.posix.join('{{hostBaseUrl}}', resolvedResourcePath);
237+
const absoluteResourcePath = getAbsoluteResourcePath(elem, resourcePath);
242238
$(this).attr('href', absoluteResourcePath);
243239
});
244240
return $.html();
@@ -256,20 +252,18 @@ class Parser {
256252
}
257253

258254
_parse(node, context, config) {
259-
const element = node;
260-
const self = this;
261-
if (_.isArray(element)) {
262-
return element.map(el => self._parse(el, context, config));
255+
if (_.isArray(node)) {
256+
return node.map(el => this._parse(el, context, config));
263257
}
264-
if (Parser.isText(element)) {
265-
return element;
258+
if (Parser.isText(node)) {
259+
return node;
266260
}
267-
if (element.name) {
268-
element.name = element.name.toLowerCase();
261+
if (node.name) {
262+
node.name = node.name.toLowerCase();
269263
}
270264

271-
if ((/^h[1-6]$/).test(element.name) && !element.attribs.id) {
272-
const textContent = utils.getTextContent(element);
265+
if ((/^h[1-6]$/).test(node.name) && !node.attribs.id) {
266+
const textContent = utils.getTextContent(node);
273267
const slugifiedHeading = slugify(textContent, { decamelize: false });
274268

275269
let headerId = slugifiedHeading;
@@ -281,59 +275,58 @@ class Parser {
281275
headerIdMap[slugifiedHeading] = 2;
282276
}
283277

284-
element.attribs.id = headerId;
278+
node.attribs.id = headerId;
285279
}
286280

287-
switch (element.name) {
281+
switch (node.name) {
288282
case 'md':
289-
element.name = 'span';
283+
node.name = 'span';
290284
cheerio.prototype.options.xmlMode = false;
291-
element.children = cheerio.parseHTML(md.renderInline(cheerio.html(element.children)), true);
285+
node.children = cheerio.parseHTML(md.renderInline(cheerio.html(node.children)), true);
292286
cheerio.prototype.options.xmlMode = true;
293287
break;
294288
case 'markdown':
295-
element.name = 'div';
289+
node.name = 'div';
296290
cheerio.prototype.options.xmlMode = false;
297-
element.children = cheerio.parseHTML(md.render(cheerio.html(element.children)), true);
291+
node.children = cheerio.parseHTML(md.render(cheerio.html(node.children)), true);
298292
cheerio.prototype.options.xmlMode = true;
299293
break;
300294
case 'panel': {
301-
if (!_.hasIn(element.attribs, 'src')) { // dynamic panel
295+
if (!_.hasIn(node.attribs, 'src')) { // dynamic panel
302296
break;
303297
}
304-
const fileExists = utils.fileExists(element.attribs.src)
298+
const fileExists = utils.fileExists(node.attribs.src)
305299
|| utils.fileExists(
306300
urlUtils.calculateBoilerplateFilePath(
307-
element.attribs.boilerplate,
308-
element.attribs.src, config));
301+
node.attribs.boilerplate,
302+
node.attribs.src, config));
309303
if (fileExists) {
310-
const { src, fragment } = element.attribs;
304+
const { src, fragment } = node.attribs;
311305
const resultDir = path.dirname(path.join('{{hostBaseUrl}}', path.relative(config.rootPath, src)));
312306
const resultPath = path.join(resultDir, utils.setExtension(path.basename(src), '._include_.html'));
313-
element.attribs.src = utils.ensurePosix(fragment ? `${resultPath}#${fragment}` : resultPath);
307+
node.attribs.src = utils.ensurePosix(fragment ? `${resultPath}#${fragment}` : resultPath);
314308
}
315-
delete element.attribs.boilerplate;
309+
delete node.attribs.boilerplate;
316310
break;
317311
}
318312
default:
319313
break;
320314
}
321315

322-
componentParser.parseComponents(element, this._onError);
316+
componentParser.parseComponents(node, this._onError);
323317

324-
if (element.children) {
325-
element.children.forEach((child) => {
326-
self._parse(child, context, config);
318+
if (node.children) {
319+
node.children.forEach((child) => {
320+
this._parse(child, context, config);
327321
});
328322
}
329323

330-
componentParser.postParseComponents(element, this._onError);
324+
componentParser.postParseComponents(node, this._onError);
331325

332-
return element;
326+
return node;
333327
}
334328

335329
_trimNodes(node) {
336-
const self = this;
337330
if (node.name === 'pre' || node.name === 'code') {
338331
return;
339332
}
@@ -346,7 +339,7 @@ class Parser {
346339
node.children.splice(n, 1);
347340
n--;
348341
} else if (child.type === 'tag') {
349-
self._trimNodes(child);
342+
this._trimNodes(child);
350343
}
351344
}
352345
/* eslint-enable no-plusplus */
@@ -589,21 +582,20 @@ class Parser {
589582
}
590583

591584
_rebaseReference(node, foundBase) {
592-
const element = node;
593-
if (_.isArray(element)) {
594-
return element.map(el => this._rebaseReference(el, foundBase));
585+
if (_.isArray(node)) {
586+
return node.map(el => this._rebaseReference(el, foundBase));
595587
}
596-
if (Parser.isText(element)) {
597-
return element;
588+
if (Parser.isText(node)) {
589+
return node;
598590
}
599591
// Rebase children element
600592
const childrenBase = {};
601-
element.children.forEach((el) => {
593+
node.children.forEach((el) => {
602594
this._rebaseReference(el, childrenBase);
603595
});
604596
// rebase current element
605-
if (element.attribs[ATTRIB_INCLUDE_PATH]) {
606-
const filePath = element.attribs[ATTRIB_INCLUDE_PATH];
597+
if (node.attribs[ATTRIB_INCLUDE_PATH]) {
598+
const filePath = node.attribs[ATTRIB_INCLUDE_PATH];
607599
let newBaseUrl = urlUtils.calculateNewBaseUrls(filePath, this.rootPath, this.baseUrlMap);
608600
if (newBaseUrl) {
609601
const { relative, parent } = newBaseUrl;
@@ -616,27 +608,27 @@ class Parser {
616608
if (bases.length !== 0) {
617609
// need to rebase
618610
newBaseUrl = combinedBases[bases[0]];
619-
if (element.children) {
611+
if (node.children) {
620612
// ATTRIB_CWF is where the element was preprocessed
621-
const currentBase = urlUtils.calculateNewBaseUrls(element.attribs[ATTRIB_CWF],
613+
const currentBase = urlUtils.calculateNewBaseUrls(node.attribs[ATTRIB_CWF],
622614
this.rootPath, this.baseUrlMap);
623615
if (currentBase && currentBase.relative !== newBaseUrl) {
624616
cheerio.prototype.options.xmlMode = false;
625-
const rendered = nunjucks.renderString(cheerio.html(element.children), {
617+
const rendered = nunjucks.renderString(cheerio.html(node.children), {
626618
// This is to prevent the nunjuck call from converting {{hostBaseUrl}} to an empty string
627619
// and let the hostBaseUrl value be injected later.
628620
hostBaseUrl: '{{hostBaseUrl}}',
629621
baseUrl: `{{hostBaseUrl}}/${newBaseUrl}`,
630622
}, { path: filePath });
631-
element.children = cheerio.parseHTML(rendered, true);
623+
node.children = cheerio.parseHTML(rendered, true);
632624
cheerio.prototype.options.xmlMode = true;
633625
}
634626
}
635627
}
636-
delete element.attribs[ATTRIB_INCLUDE_PATH];
628+
delete node.attribs[ATTRIB_INCLUDE_PATH];
637629
}
638-
delete element.attribs[ATTRIB_CWF];
639-
return element;
630+
delete node.attribs[ATTRIB_CWF];
631+
return node;
640632
}
641633

642634
static resetVariables() {
@@ -645,8 +637,8 @@ class Parser {
645637
Parser.PROCESSED_INNER_VARIABLES.clear();
646638
}
647639

648-
static isText(element) {
649-
return element.type === 'text' || element.type === 'comment';
640+
static isText(node) {
641+
return node.type === 'text' || node.type === 'comment';
650642
}
651643

652644
/**

0 commit comments

Comments
 (0)