Symbol.toPrimitive
method, invoked within tagged template literal loses access to the closure.
To reproduce, simply paste the provided code snippet in dev console, run it with and without tag-function. Any relevant articles are highly appreciated.
P.S. I would also appreciate if you give me an idea how and where to debug js code (including node.js). I'm interested in lexical environment, execution context and call stack.
const isEmptyString = /^\s*$/;
class Thread {
constructor() {
this.scope = {
current: '/test|0::0'
};
this.context = {
current: '/test|0'
};
this.html = (strings, ...interpolations) => {
var output = '';
var prevMode = this._mode;
this._mode = 'html';
var {
length
} = interpolations;
output += strings[0]
for (let i = 0; i < length; ++i) {
output += String(interpolations[i]) + strings[i + 1];
}
this._mode = prevMode;
return output;
};
}
get id() {
var fragment;
const scope = this.scope.current;
const context = this.context.current;
return Object.defineProperties(function self(newFragment) {
fragment = newFragment;
return self;
}, {
scope: {
get() {
return scope
}
},
context: {
get() {
return context
}
},
fragment: {
get() {
return fragment
}
},
[Symbol.toPrimitive]: {
value: hint => {
console.log('::', fragment, '::');
const isFragmentDefined = !isEmptyString.test(fragment);
const quote = isFragmentDefined ? '\'' : '';
const suffix = isFragmentDefined ? `::${fragment}` : '';
if (isFragmentDefined) fragment = '';
switch (true) {
case this._mode === 'html':
return `node=${quote}${scope}${suffix}${quote}`;
case this._mode === 'css':
return `${context}${suffix}`.replace(invalidCSS, char => `\\${char}`);
default:
return `${scope}${suffix}`;
}
}
}
});
}
}
let thread = new Thread();
async function article() {
let {
id,
html
} = thread;
let links = html `
<ul><li ${id('C-first-id')}></li><li ${id('C-second-id')}></li><li ${id('C-third-id')}></li><li ${id('C-fourth-id')}></li></ul>
`;
return html `
<article><h1 ${id('B-first-id')}>Some header</h1><p ${id('B-second-id')}>Lorem ipsum...</p><p ${id('B-third-id')}>Lorem ipsum...</p><p ${id('B-fourth-id')}>Lorem ipsum...</p><section>
${links}</section></article>
`;
}
async function content() {
let {
id,
html
} = thread;
return html `
<main><div><h1 ${id('A-first-id')}>Last article</h1><div><a href='#' ${id('A-second-id')}>More articles like this</a>
${await article()}<a href='#' ${id('A-third-id')}>Something else...</a><a href='#' ${id('A-fourth-id')}>Something else...</a></div></div></main>
`;
}
content();