vaderjs 1.2.9 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/vader-min.js +1 -0
- package/vader.js +159 -132
- package/worker-min.js +1 -0
- package/worker.js +59 -9
- package/snippet-gen/vader/.vscode/launch.json +0 -17
- package/snippet-gen/vader/.vscodeignore +0 -4
- package/snippet-gen/vader/CHANGELOG.md +0 -9
- package/snippet-gen/vader/README.md +0 -26
- package/snippet-gen/vader/extension/extension.js +0 -70
- package/snippet-gen/vader/extension/html_completion/html_completion.js +0 -91
- package/snippet-gen/vader/extension/html_completion/html_completion.json +0 -1891
- package/snippet-gen/vader/icons/logo.png +0 -0
- package/snippet-gen/vader/language-configuration.json +0 -128
- package/snippet-gen/vader/package.json +0 -47
- package/snippet-gen/vader/snippets/vader.json +0 -13
- package/snippet-gen/vader/syntaxes/vader.tmLanguage.json +0 -2644
package/package.json
CHANGED
package/vader-min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let dom=[],states={},worker=new Worker(new URL("./worker.js",import.meta.url));function markdown(e){let t=e.match(/(#+)(.*)/g);return t&&t.forEach((t=>{if(t.includes("/")||t.includes("<")||t.includes(">"))return;let s=t.split("#").length;e=e.replace(t,`<h${s} class="markdown_heading">${t.replace(/#/g,"")}</h${s}>`)})),e=(e=(e=(e=(e=(e=(e=e.replace(/\*\*(.*?)\*\*/g,((e,t)=>`<b class="markdown_bold">${t}</b>`))).replace(/\*(.*?)\*/g,((e,t)=>`<i class="markdown_italic">${t}</i>`))).replace(/`(.*?)`/g,((e,t)=>`<code>${t}</code>`))).replace(/\[([^\]]+)\]\(([^)]+)\)/g,((e,t,s)=>`<a class="markdown_link" href="${s}">${t}</a>`))).replace(/!\[([^\]]+)\]\(([^)]+)\)/g,((e,t,s)=>`<img class="markdown_image" src="${s}" alt="${t}" />`))).split("\n").map(((e,t,s)=>e.match(/^\s*-\s+(.*?)$/gm)?0!==t&&s[t-1].match(/^\s*-\s+(.*?)$/gm)?t!==s.length-1&&s[t+1].match(/^\s*-\s+(.*?)$/gm)?`<li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`:`<li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li></ul>`:`<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`:e)).join("\n")).split("\n").map(((e,t,s)=>e.match(/^\s*\d+\.\s+(.*?)$/gm)?0!==t&&s[t-1].match(/^\s*\d+\.\s+(.*?)$/gm)?t!==s.length-1&&s[t+1].match(/^\s*\d+\.\s+(.*?)$/gm)?`<li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`:`<li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li></ol>`:`<ol class="markdown_ordered" style="list-style-type:decimal;"><li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`:e)).join("\n")}export const useRef=e=>{const t=document.querySelector(`[ref="${e}"]`);return{current:t,update:e=>{const s=(new DOMParser).parseFromString(e,"text/html").body.firstChild;if(t){!s.isEqualNode(t)&&t.parentNode.replaceChild(s,t)}}}};let components=[];export class Component{constructor(){this.states={},this.name=this.constructor.name,this.executedEffects={},this.storedProps={},this.componentMounted=!1,this.hasMounted=!1,this.$_signal_subscribers=[],this.$_signal_subscribers_ran=[],this.effects={},this.$_useStore_subscribers=[],this.init(),this.Componentcontent=null,this.$_signal_dispatch_event=new CustomEvent("signalDispatch",{detail:{hasUpdated:!1,state:null}}),this.snapshots=[],this.dom=[],this.cfr=!1}adapter(){}init(){this.registerComponent()}registerComponent(){components.push(this)}setState(e,t){this.states[e]=t,this.updateComponent()}unmount(){this.componentMounted=!1,this.componentWillUnmount(),document.querySelector(`[data-component="${this.name}"]`).remove(),document.querySelector(`[data-component="${this.name}"]`)||(components=components.filter((e=>e.name!==this.name)))}componentUpdate(e,t,s){}componentDidMount(){}componentWillUnmount(){}signal=(e,t)=>{let s=!1,[r,n]=this.useState(e,t,(()=>{if(this.$_signal_subscribers.length>0){for(var e=0;e<this.$_signal_subscribers.length;e++)if(!s){if(this.$_signal_subscribers[e].runonce&&this.$_signal_subscribers_ran.includes(this.$_signal_subscribers[e]))break;return this.$_signal_subscribers[e].function(r),void this.$_signal_subscribers_ran.push(this.$_signal_subscribers[e])}}else this.$_signal_dispatch_event.detail.hasUpdated=!0,this.$_signal_dispatch_event.detail.state=r,window.dispatchEvent(this.$_signal_dispatch_event)}));return this.$_signal_subscribe=(e,t)=>{this.$_signal_subscribers.push({function:e,runonce:t})},this.$_signal_cleanup=e=>{this.$_signal_subscribers=this.$_signal_subscribers.filter((t=>t.function!==e))},this.$_signal_dispatch=()=>{for(var e=0;e<this.$_signal_subscribers.length&&(!this.$_signal_subscribers[e].runonce||!this.$_signal_subscribers_ran.includes(this.$_signal_subscribers[e]));e++)this.$_signal_subscribers[e].function(r),this.$_signal_subscribers_ran.push(this.$_signal_subscribers[e])},this.$_signal_get=()=>r,this.$_signal_call=()=>{s=!0,this.$_signal_dispatch()},this.$_signal_set=e=>{n(e)},{subscribe:this.$_signal_subscribe,cleanup:this.$_signal_cleanup,dispatch:this.$_signal_dispatch,call:this.$_signal_call,set:this.$_signal_set,get:this.$_signal_get}};useAuth(e){let t=e.rulesets;if(!t)throw new Error("No rulesets provided");let s=e.user,r={can:e=>{let r=!1;return t.forEach((t=>{t.action===e&&t.condition(s)&&(r=!0)})),r},hasRole:e=>s.role&&s.role.includes(e),canWithRole:(e,t)=>r.can(e)&&r.hasRole(t),assignRule:e=>{t.some((t=>t.action===e.action))||t.push(e)},revokeRule:e=>{t=t.filter((t=>t.action!==e))},canAnyOf:e=>e.some((e=>r.can(e))),canAllOf:e=>e.every((e=>r.can(e))),canGroup:(e,t="any")=>"any"===t?r.canAnyOf(e):r.canAllOf(e)};return r}useReducer(e,t,s){return this.states[e]||(this.states[e]=s),[this.states[e],s=>{this.states[e]=t(this.states[e],s),this.updateComponent()}]}runEffects(){Object.keys(this.effects).forEach((e=>{this.effects[e].forEach((e=>{this.executedEffects[e]||(e(),this.executedEffects[e]=!0)}))}))}useSyncStore(e,t){let[s,r]=this.useState(e,t||localStorage.getItem(`$_vader_${e}`,(t=>{localStorage.setItem(`$_vader_${e}`,JSON.stringify(t)),this.$_useStore_subscribers.forEach((e=>{e(t)}))}))||{});return{getField:e=>s[e],setField:(e,t)=>{const n={...s,[e]:t};r(n)},subscribe:e=>this.$_useStore_subscribers.push(e),clear:e=>{let t=s;delete t[e],r(t)}}}useState(e,t,s=null){return this.states[e]||(this.states[e]=t),[this.states[e],t=>{this.states[e]=t,this.updateComponent(),"function"==typeof s&&s()}]}useRef(e){console.log(this.dom);const t=this.dom[e];return{current:()=>t,update:e=>{const s=(new DOMParser).parseFromString(e,"text/html").body.firstChild;if(t){!s.isEqualNode(t)&&t.parentNode.replaceChild(s,t)}}}}useEffect(e,t){return this.effects[this.name]||(this.effects[this.name]=[]),this.effects[this.name].push(e),t.length>0?t.forEach((e=>{if(e.set)throw new Error("signal found, do not use effect and signals at the same time - signals are more efficient")})):this.hasMounted||(e(),this.hasMounted=!0),{cleanup:()=>{this.effects[this.name]=this.effects[this.name].filter((t=>t!==e))}}}$Function(e){let t=e.name;return t||(t="anonymous"+Math.floor(1e17*Math.random())),window[t]=e,`window.${t}()`}updateComponent(){const e=document.createDocumentFragment();Object.keys(components).forEach((async t=>{const{name:s}=components[t];let r=document.querySelector(`[data-component="${s}"]`),n={name:s,time:(new Date).getTime(),prev_state:this.states,prev_props:this.storedProps,content:r.innerHTML};if(!r)return;const i=await new Function("useState","useEffect","useAuth","useReducer","useSyncStore","signal","rf","props","render","return `"+await this.render()+"`;")(this.useState,this.useEffect,this.useAuth,this.useReducer,this.useSyncStore,this.signal,this.render);if(i!==r.innerHTML){if(this.snapshots.length>0){this.snapshots[this.snapshots.length-1]!==n&&this.snapshots.push(n)}else this.snapshots.push(n);this.componentUpdate(n.prev_state,n.prev_props,n.content),e.appendChild(document.createRange().createContextualFragment(i)),r.innerHTML="",r.appendChild(e),this.runEffects()}}))}validateClassName(e){return/^[a-zA-Z0-9-_]+$/.test(e)}parseHTML(e){const t=(new DOMParser).parseFromString(e,"text/html");console.log(t);return t.documentElement.querySelectorAll("*").forEach((e=>{if("IMG"===e.nodeName){if(!e.hasAttribute("alt")&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_accessibility --\x3e"))throw new SyntaxError(`Image: ${e.outerHTML} missing alt attribute`);if(e.hasAttribute("alt")&&e.getAttribute("alt").length<1&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_accessibility --\x3e"))throw new SyntaxError(`Image: ${e.outerHTML} alt attribute cannot be empty`);if(e.hasAttribute("src")&&!e.getAttribute("src")?.includes("http")||!e.getAttribute("src")?.includes("https")&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_accessibility --\x3e")){let t=e.getAttribute("src");e.setAttribute("aria-hidden","true"),e.setAttribute("hidden","true");let s=window.location.origin+window.location.pathname.replace(/\/[^\/]*$/,"")+"/public/"+e.getAttribute("src"),r=new Image;r.src=s,r.onerror=()=>{throw e.setAttribute("src",t),new Error(`Image: ${e.outerHTML} not found`)},e.setAttribute("src",s),r.onload=()=>{document.querySelectorAll(`img[src="${s}"]`).forEach((e=>{e.setAttribute("src",s),e.removeAttribute("aria-hidden"),e.removeAttribute("hidden")}))}}}else{if(e.hasAttribute("ref")&&(t[e.getAttribute("ref")]=e),"MARKDOWN"===e.nodeName&&(e.innerHTML=markdown(e.innerHTML.replace(/\\n/g,"\n").trim())),e.hasAttribute("class")){if(!document.documentElement.outerHTML.includes("\x3c!-- #vader-allow_class --\x3e"))throw console.warn("you can disable class errors using, \x3c!-- #vader-allow_class --\x3e"),new Error("class attribute is not allowed, please use className instead")}else e.hasAttribute("className")&&(e.setAttribute("class",e.getAttribute("className")),e.removeAttribute("className"));e.hasAttribute("href")&&e.getAttribute("href").startsWith("/")&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_relative-paths --\x3e")&&e.setAttribute("href",`#/${e.getAttribute("href").replace("/","")}`),!e.hasAttribute("src")||e.getAttribute("src").includes("http")||e.getAttribute("src").includes("https")||document.documentElement.outerHTML.includes("\x3c!-- #vader-disable_relative-paths --\x3e")||e.setAttribute("src",`./public/${e.getAttribute("src")}`)}})),e=t.body.innerHTML,this.Componentcontent=e,e.includes("<div data-component")||(e=`<div data-component="${this.name}">${e}</div>`),markdown(e.replace(/\\n/g,"\n").trim())}html(e,...t){let s=setInterval((()=>{document.querySelector(`[data-component="${this.name}"]`)&&(clearInterval(s),this.componentMounted=!0,document.querySelector(`[data-component="${this.name}"]`)?.querySelectorAll("*").forEach((e=>{e.hasAttribute("ref")&&(this.dom[e.getAttribute("ref")]=e)})),this.componentDidMount())}),100),r=document.createElement("script");r.setAttribute("type","text/javascript"),r.setAttribute("data-component-script",this.name);this.dom;if(this.cfr){worker.postMessage({strings:e,args:t,location:window.location.origin+window.location.pathname.replace(/\/[^\/]*$/,"")+"/public/",name:this.name});let s=new Promise(((e,t)=>{worker.onmessage=t=>{if(t.data.error)throw new Error(t.data.error);this.dom;console.log(this.dom);let s=t.data.js,r=t.data.template;const n=this.useState.bind(this),i=this.useEffect.bind(this),a=this.useReducer.bind(this),o=this.useAuth.bind(this),c=this.useSyncStore.bind(this),l=this.signal.bind(this),u=this.$Function.bind(this);let h=this.states;const d=this.useRef.bind(this);new Function("useState","useEffect","useAuth","useReducer","useSyncStore","signal","rf","dom","render","states","useRef",s)(n,i,o,a,c,l,u,this.dom,this.render,this.states,d),e(new Function("useRef","states","return`"+r+"`")(d,h))},worker.onerror=e=>{t(e)}}));return s}{let s="";for(let r=0;r<e.length;r++)s+=e[r],r<t.length&&(s+=t[r]);return s=new Function("useRef",`return \`${s}\``)(useRef),s.trim().startsWith("<body>")||console.warn("You should wrap your html in a body tag, vader may not grab all html!"),this.parseHTML(s)}}async render(e){}}const Vader={Component:Component,useRef:useRef};export const component=e=>new Component;export const rf=(e,t)=>{window[e]=t};let cache={};async function handletemplate(e){let t=(new DOMParser).parseFromString(e,"text/html"),s=t.documentElement.querySelectorAll("*");if(s.length>0)for(var r=0;r<s.length;r++)if("INCLUDE"===s[r].nodeName){if(!s[r].getAttribute("src")||""===s[r].getAttribute("src"))throw new Error("Include tag must have src attribute");let e=s[r].getAttribute("src")?.split("/").pop()?.split(".")[0],n=await include(s[r].getAttribute("src"));n=n.replace(/`/g,"\\`"),cache[s[r].getAttribute("src")]=n,n=new Function(`return \`${n}\`;`)();let i=(new DOMParser).parseFromString(n,"text/html");i.querySelectorAll("include").forEach((e=>{e.remove()})),t.querySelectorAll(e).forEach((e=>{if(e.attributes.length>0)for(var s=0;s<e.attributes.length;s++)i.body.outerHTML=i.body.outerHTML.replace(`{{${e.attributes[s].name}}}`,e.attributes[s].value);if(e.children.length>0&&i.body.querySelector("slot"))for(s=0;s<e.children.length;s++){i.body.querySelectorAll("slot").forEach((t=>{t.getAttribute("id")===e.nodeName.toLowerCase()&&(t.outerHTML=`<div>${e.innerHTML}</div>`)}))}t.body.querySelectorAll("include").forEach((e=>{e.remove()})),t.body.outerHTML=t.body.outerHTML.replace(/`/g,"\\`"),t.body.outerHTML=t.body.outerHTML.replace(e.outerHTML,new Function(`return \`${i.body.outerHTML}\`;`)())}))}return t.body.outerHTML=t.body.outerHTML.replace(/`/g,"\\`"),e=new Function(`return \`${t.body.outerHTML}\`;`)()}export const include=async e=>(!e.startsWith("/")||e.includes("/src/")||document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_relative-paths --\x3e")||(e="/src/"+e),cache[e]?await handletemplate(new Function(`return \`${cache[e]}\`;`)()):fetch(`./${e}`).then((t=>{if(404===t.status)throw new Error(`No file found at ${e}`);return t.text()})).then((async t=>(cache[e]=t,t=await handletemplate(new Function(`return \`${t}\`;`)())))));export default Vader;
|
package/vader.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
let dom =
|
|
1
|
+
let dom = []
|
|
2
2
|
let states = {};
|
|
3
3
|
let worker = new Worker(new URL('./worker.js', import.meta.url));
|
|
4
4
|
/**
|
|
@@ -7,125 +7,65 @@ let worker = new Worker(new URL('./worker.js', import.meta.url));
|
|
|
7
7
|
* @description Allows you to convert markdown to html
|
|
8
8
|
*/
|
|
9
9
|
function markdown(content) {
|
|
10
|
-
const lines = content.split('\n').filter((line) => line !== '').map((line) => line.trim());
|
|
11
|
-
|
|
12
|
-
let result = '';
|
|
13
|
-
|
|
14
|
-
lines.forEach((line) => {
|
|
15
|
-
let heading = line.match(/^#{1,6}\s/);
|
|
16
|
-
let bold = line.match(/\*\*(.*?)\*\*/g);
|
|
17
|
-
let italic = line.match(/\*(.*?)\*/g);
|
|
18
|
-
|
|
19
|
-
let link = line.match(/\[(.*?)\]\((.*?)\)/g);
|
|
20
|
-
let ul = line.match(/^\-\s/);
|
|
21
|
-
let ol = line.match(/^\d\.\s/);
|
|
22
10
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
let codeBlock = line.match(/\`\`\`/g);
|
|
30
|
-
let codeBlockEnd = line.match(/\`\`\`/g);
|
|
31
|
-
let code = line.match(/\`(.*?)\`/g);
|
|
32
|
-
|
|
11
|
+
let headers = content.match(/(#+)(.*)/g);
|
|
12
|
+
if (headers) {
|
|
13
|
+
headers.forEach((header) => {
|
|
14
|
+
if(header.includes('/') || header.includes('<') || header.includes('>')){
|
|
15
|
+
return
|
|
33
16
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
line += `</h${headingLevel}>`;
|
|
40
|
-
}
|
|
41
|
-
if (bold) {
|
|
42
|
-
bold.forEach((b) => {
|
|
43
|
-
line = line.replace(b, `<strong
|
|
44
|
-
className="$vader_markdown_bold"
|
|
45
|
-
>${b.replace(/\*\*/g, "")}</strong>`);
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
if (italic) {
|
|
49
|
-
italic.forEach((i) => {
|
|
50
|
-
line = line.replace(i, `<em
|
|
51
|
-
className="$vader_markdown_italic"
|
|
52
|
-
>${i.replace(/\*/g, "")}</em>`);
|
|
53
|
-
});
|
|
54
|
-
}
|
|
17
|
+
}
|
|
18
|
+
let level = header.split('#').length;
|
|
19
|
+
content = content.replace(header, `<h${level} class="markdown_heading">${header.replace(/#/g, '')}</h${level}>`);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
55
22
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
if (blockquote) {
|
|
84
|
-
line = line.replace(blockquote[0], `<blockquote
|
|
85
|
-
className="$vader_markdown_blockquote"
|
|
86
|
-
>`);
|
|
87
|
-
line += `</blockquote>`;
|
|
88
|
-
}
|
|
89
|
-
if (image) {
|
|
90
|
-
image.forEach((i) => {
|
|
91
|
-
// @ts-ignore
|
|
92
|
-
let alt = i.match(/\[(.*?)\]/g)[0].replace(/\[|\]/g, "");
|
|
93
|
-
// @ts-ignore
|
|
94
|
-
let src = i.match(/\((.*?)\)/g)[0].replace(/\(|\)/g, "");
|
|
95
|
-
i.replace(i, `<img src="${src}" alt="${alt}"/>`);
|
|
96
|
-
line = line.replace(i, `<img
|
|
97
|
-
className="$vader_markdown_image"
|
|
98
|
-
src="${src}" alt="${alt}"/>`).replace('!','')
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
if (li) {
|
|
102
|
-
line = line.replace(li[0], `<li>`);
|
|
103
|
-
line += `</li>`;
|
|
104
|
-
}
|
|
105
|
-
if (codeBlock) {
|
|
106
|
-
line = line.replace(codeBlock[0], `<pre className="$vader_markdown_code_block" ><code>`);
|
|
107
|
-
}
|
|
108
|
-
if (codeBlockEnd) {
|
|
109
|
-
line = line.replace(codeBlockEnd[0], `</code></pre>`);
|
|
23
|
+
content = content.replace(/\*\*(.*?)\*\*/g, (match, text) => {
|
|
24
|
+
return `<b class="markdown_bold">${text}</b>`;
|
|
25
|
+
});
|
|
26
|
+
content = content.replace(/\*(.*?)\*/g, (match, text) => {
|
|
27
|
+
return `<i class="markdown_italic">${text}</i>`;
|
|
28
|
+
})
|
|
29
|
+
content = content.replace(/`(.*?)`/g, (match, text) => {
|
|
30
|
+
return `<code>${text}</code>`;
|
|
31
|
+
});
|
|
32
|
+
content = content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, url) => {
|
|
33
|
+
return `<a class="markdown_link" href="${url}">${text}</a>`;
|
|
34
|
+
});
|
|
35
|
+
content = content.replace(/!\[([^\]]+)\]\(([^)]+)\)/g, (match, alt, src) => {
|
|
36
|
+
return `<img class="markdown_image" src="${src}" alt="${alt}" />`;
|
|
37
|
+
});
|
|
38
|
+
content = content.split('\n').map((line, index, arr) => {
|
|
39
|
+
if (line.match(/^\s*-\s+(.*?)$/gm)) {
|
|
40
|
+
if (index === 0 || !arr[index - 1].match(/^\s*-\s+(.*?)$/gm)) {
|
|
41
|
+
return `<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li>`;
|
|
42
|
+
} else if (index === arr.length - 1 || !arr[index + 1].match(/^\s*-\s+(.*?)$/gm)) {
|
|
43
|
+
return `<li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li></ul>`;
|
|
44
|
+
} else {
|
|
45
|
+
return `<li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li>`;
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
return line;
|
|
110
49
|
}
|
|
50
|
+
}).join('\n');
|
|
111
51
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
52
|
+
content = content.split('\n').map((line, index, arr) => {
|
|
53
|
+
if (line.match(/^\s*\d+\.\s+(.*?)$/gm)) {
|
|
54
|
+
if (index === 0 || !arr[index - 1].match(/^\s*\d+\.\s+(.*?)$/gm)) {
|
|
55
|
+
return `<ol class="markdown_ordered" style="list-style-type:decimal;"><li>${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}</li>`;
|
|
56
|
+
} else if (index === arr.length - 1 || !arr[index + 1].match(/^\s*\d+\.\s+(.*?)$/gm)) {
|
|
57
|
+
return `<li>${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}</li></ol>`;
|
|
58
|
+
} else {
|
|
59
|
+
return `<li>${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}</li>`;
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
return line;
|
|
120
63
|
}
|
|
121
|
-
|
|
122
|
-
|
|
64
|
+
}).join('\n');
|
|
123
65
|
|
|
124
66
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return result;
|
|
67
|
+
return content
|
|
68
|
+
|
|
129
69
|
}
|
|
130
70
|
|
|
131
71
|
|
|
@@ -208,6 +148,13 @@ export class Component {
|
|
|
208
148
|
},
|
|
209
149
|
});
|
|
210
150
|
this.snapshots = [];
|
|
151
|
+
/**
|
|
152
|
+
* @property {Object} dom
|
|
153
|
+
* @description Allows you to get reference to DOM element
|
|
154
|
+
* @returns {void | HTMLElement}
|
|
155
|
+
*
|
|
156
|
+
*/
|
|
157
|
+
this.dom = []
|
|
211
158
|
|
|
212
159
|
/**
|
|
213
160
|
* @property {Boolean} cfr
|
|
@@ -562,6 +509,8 @@ export class Component {
|
|
|
562
509
|
},
|
|
563
510
|
];
|
|
564
511
|
}
|
|
512
|
+
|
|
513
|
+
|
|
565
514
|
runEffects() {
|
|
566
515
|
Object.keys(this.effects).forEach((component) => {
|
|
567
516
|
this.effects[component].forEach((effect) => {
|
|
@@ -572,6 +521,7 @@ export class Component {
|
|
|
572
521
|
});
|
|
573
522
|
});
|
|
574
523
|
}
|
|
524
|
+
|
|
575
525
|
/**
|
|
576
526
|
* @method useSyncStore
|
|
577
527
|
* @description Allows you to create a store
|
|
@@ -660,8 +610,50 @@ export class Component {
|
|
|
660
610
|
},
|
|
661
611
|
];
|
|
662
612
|
}
|
|
613
|
+
/**
|
|
614
|
+
* @method useRef
|
|
615
|
+
* @memberof Component
|
|
616
|
+
* @param {string} ref
|
|
617
|
+
* @description Allows you to get reference to DOM elements from the dom array
|
|
618
|
+
* @returns {Object} {current, update}
|
|
619
|
+
* @example
|
|
620
|
+
* let ref = this.useRef('ref')
|
|
621
|
+
* ref.current // returns the DOM element
|
|
622
|
+
|
|
623
|
+
*/
|
|
624
|
+
|
|
625
|
+
useRef(ref) {
|
|
626
|
+
// get ref from array
|
|
627
|
+
console.log(this.dom)
|
|
628
|
+
const element = this.dom[ref]
|
|
629
|
+
|
|
630
|
+
const getElement = () => element;
|
|
631
|
+
|
|
632
|
+
const update = (data) => {
|
|
633
|
+
const newDom = new DOMParser().parseFromString(data, "text/html");
|
|
634
|
+
const newElement = newDom.body.firstChild;
|
|
635
|
+
|
|
636
|
+
if (element) {
|
|
637
|
+
// @ts-ignore
|
|
638
|
+
const isDifferent = !newElement.isEqualNode(element);
|
|
639
|
+
if (isDifferent) {
|
|
640
|
+
// @ts-ignore
|
|
641
|
+
element.parentNode.replaceChild(newElement, element);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
return {
|
|
647
|
+
/**@type {HTMLElement} */
|
|
648
|
+
// @ts-ignore
|
|
649
|
+
current: getElement,
|
|
650
|
+
/**@type {Function} */
|
|
651
|
+
update,
|
|
652
|
+
};
|
|
653
|
+
}
|
|
663
654
|
|
|
664
655
|
/**
|
|
656
|
+
*
|
|
665
657
|
* @function useEffect
|
|
666
658
|
* @param {*} effectFn
|
|
667
659
|
* @param {*} dependencies
|
|
@@ -726,11 +718,12 @@ export class Component {
|
|
|
726
718
|
const fragment = document.createDocumentFragment();
|
|
727
719
|
Object.keys(components).forEach(async (component) => {
|
|
728
720
|
const { name } = components[component];
|
|
729
|
-
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
let componentContainer = document.querySelector(
|
|
730
724
|
`[data-component="${name}"]`
|
|
731
725
|
);
|
|
732
|
-
|
|
733
|
-
let time = new Date().getTime().toLocaleString();
|
|
726
|
+
let time = new Date().getTime();
|
|
734
727
|
/**
|
|
735
728
|
* @property {Object} snapshot
|
|
736
729
|
* @description Allows you to keep track of component snapshots
|
|
@@ -989,22 +982,28 @@ export class Component {
|
|
|
989
982
|
|
|
990
983
|
html(strings, ...args) {
|
|
991
984
|
// @ts-ignore
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
}
|
|
985
|
+
let tiemr = setInterval(()=>{
|
|
986
|
+
if(document.querySelector(`[data-component="${this.name}"]`)){
|
|
987
|
+
clearInterval(tiemr)
|
|
988
|
+
this.componentMounted = true;
|
|
989
|
+
|
|
990
|
+
document.querySelector(`[data-component="${this.name}"]`)?.querySelectorAll("*").forEach((element)=>{
|
|
991
|
+
if(element.hasAttribute("ref")){
|
|
992
|
+
// @ts-ignore
|
|
993
|
+
this.dom[element.getAttribute("ref")] = element
|
|
994
|
+
}
|
|
995
|
+
})
|
|
996
|
+
this.componentDidMount();
|
|
997
|
+
}
|
|
998
|
+
}, 100)
|
|
999
|
+
let script = document.createElement("script");
|
|
1000
|
+
script.setAttribute("type", "text/javascript");
|
|
1001
|
+
script.setAttribute(`data-component-script`, this.name);
|
|
1002
|
+
|
|
1006
1003
|
|
|
1007
1004
|
|
|
1005
|
+
let dom = this.dom
|
|
1006
|
+
|
|
1008
1007
|
if(this.cfr){
|
|
1009
1008
|
|
|
1010
1009
|
worker.postMessage({strings, args, location: window.location.origin + window.location.pathname.replace(/\/[^\/]*$/, '') + '/public/', name: this.name})
|
|
@@ -1013,11 +1012,39 @@ export class Component {
|
|
|
1013
1012
|
if(e.data.error){
|
|
1014
1013
|
throw new Error(e.data.error)
|
|
1015
1014
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1015
|
+
const dom = this.dom; // Assuming this.dom is an object
|
|
1016
|
+
console.log(this.dom)
|
|
1017
|
+
let js = e.data.js
|
|
1018
|
+
let template = e.data.template
|
|
1019
|
+
// Bind the component's context
|
|
1020
|
+
|
|
1021
|
+
const useState = this.useState.bind(this); // Bind the component's context
|
|
1022
|
+
const useEffect = this.useEffect.bind(this); // Bind the component's context
|
|
1023
|
+
const useReducer = this.useReducer.bind(this); // Bind the component's context
|
|
1024
|
+
const useAuth = this.useAuth.bind(this); // Bind the component's context
|
|
1025
|
+
const useSyncStore = this.useSyncStore.bind(this); // Bind the component's context
|
|
1026
|
+
const signal = this.signal.bind(this); // Bind the component's context
|
|
1027
|
+
const rf = this.$Function.bind(this); // Bind the component's context
|
|
1028
|
+
let states = this.states
|
|
1029
|
+
const useRef = this.useRef.bind(this); // Bind the component's context
|
|
1030
|
+
new Function("useState", "useEffect", "useAuth", "useReducer", "useSyncStore", "signal", "rf", "dom", "render", "states", "useRef", js)(
|
|
1031
|
+
useState,
|
|
1032
|
+
useEffect,
|
|
1033
|
+
useAuth,
|
|
1034
|
+
useReducer,
|
|
1035
|
+
useSyncStore,
|
|
1036
|
+
signal,
|
|
1037
|
+
rf,
|
|
1038
|
+
this.dom,
|
|
1039
|
+
this.render,
|
|
1040
|
+
this.states,
|
|
1041
|
+
useRef
|
|
1042
|
+
)
|
|
1043
|
+
|
|
1044
|
+
resolve(new Function("useRef", "states", "return" + "`" + template + "`")(useRef, states))
|
|
1019
1045
|
|
|
1020
1046
|
|
|
1047
|
+
|
|
1021
1048
|
|
|
1022
1049
|
}
|
|
1023
1050
|
worker.onerror = (e)=>{
|
package/worker-min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
onmessage=e=>{let a=Date.now(),l=e.data.strings,s=e.data.args,t="",r=e.data.location.split("/").slice(0,-1).join("/"),c="";for(let e=0;e<l.length;e++)c+=l[e],e<s.length&&(c+=s[e]);let o=c.match(/--([^>]*)--/gs);if(o)for(;o.length;){let e=o.pop();console.log(e),c=c.replace(e,"")}if(c=c.replace(/(#+)(.*)/g,((e,a,l)=>{if(console.log(e),e.includes("<")&&e.includes(">"))return e;{let e=a.length;return`<h ${e} class="markdown_heading">${l}</h${e}>`}})),c=c.replace(/\*\*(.*?)\*\*/g,((e,a)=>`<b class="markdown_bold">${a}</b>`)),c=c.replace(/\*(.*?)\*/g,((e,a)=>`<i class="markdown_italic">${a}</i>`)),c=c.replace(/`(.*?)`/g,((e,a)=>`<code>${a}</code>`)),c=c.replace(/\[([^\]]+)\]\(([^)]+)\)/g,((e,a,l)=>`<a class="markdown_link" href="${l}">${a}</a>`)),c=c.replace(/!\[([^\]]+)\]\(([^)]+)\)/g,((e,a,l)=>`<img class="markdown_image" src="${l}" alt="${a}" />`)),c.split("\n").forEach(((e,a,l)=>{e.match(/^\s*-\s+(.*?)$/gm)&&(c=0!==a&&l[a-1].match(/^\s*-\s+(.*?)$/gm)?a!==l.length-1&&l[a+1].match(/^\s*-\s+(.*?)$/gm)?c.replace(e,`<li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`):c.replace(e,`<li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li></ul>`):c.replace(e,`<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`))})),c.split("\n").forEach(((e,a,l)=>{e.match(/^\s*\d+\.\s+(.*?)$/gm)&&(c=0!==a&&l[a-1].match(/^\s*\d+\.\s+(.*?)$/gm)?a!==l.length-1&&l[a+1].match(/^\s*\d+\.\s+(.*?)$/gm)?c.replace(e,`<li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`):c.replace(e,`<li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li></ol>`):c.replace(e,`<ol class="markdown_ordered" style="list-style-type:decimal;"><li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`))})),c=c.replace(/^\s*-\s+(.*?)$/gm,((e,a)=>`<li class="markdown_list_item">${a}</li>`)),c=c.replace(/^\s*---\s*$/gm,'<hr class="markdown_horizontal" />'),c=c.replace(/^\s*> (.*)$/gm,((e,a)=>`<blockquote class="markdown_blockquote">${a}</blockquote>`)),c=c.replace(/((?: *\|.*?)+)\n((?: *\|.*?)+)/gm,((e,a,l)=>{const s=a.split("|").slice(1,-1),t=l.split("|").slice(1,-1);let r='<table class="markdown_table">';return r+='<thead class="markdown_table_head"><tr class="markdown_table_row">',s.forEach((e=>{r+=`<th class="markdown_table_header_cell">${e}</th>`})),r+='</tr></thead><tbody class="markdown_table_body"><tr class="markdown_table_row">',t.forEach((e=>{r+=`<td class="markdown_table_body_cell">${e}</td>`})),r+="</tr></tbody></table>",r})),!c.includes("<body>"))throw new Error(`Vader Error: You must enclose your html in a body tag for all components. \n\n${c}`);c=c.replace(/classname/g,"class");let n=c.match(/<img([^>]*)>/g);if(n)for(let a=0;a<n.length;a++){let l=n[a],s=l.match(/src="([^"]*)"/),t=l.match(/alt="([^"]*)"/);if(s){if(s[1].includes("http")&&c.includes("\x3c!-- #vader-disable_relative-paths --\x3e"))throw new Error(`Vader Error: You cannot use relative paths in the src attribute of ${s[0]}. Use absolute paths instead. \n\n${s[0]}`);c=c.replace(s[1],`${r}/${s[1]}`)}if(!t&&!c.includes("\x3c!-- #vader-disable_accessibility --\x3e"))throw new Error(`Vader Error: You must include an alt attribute in the image tag \n\n${l} of class ${e.data.name}. `);caches.match(`${r}/${s[1]}`)?console.log("already cached",caches.match(`${r}/${s[1]}`)):caches.open("vader").then((e=>{e.add(`${r}/${s[1]}`),console.log("cached",`${r}/${s[1]}`)})).catch((e=>{console.log(e)}))}let i=c.match(/href="([^"]*)"/g);if(i)for(;i.length;){let a=i.pop();if(a=a.replace('href="',"").replace('"',""),a.includes("http")&&c.includes("\x3c!-- #vader-disable_relative-paths --\x3e"))throw new Error(`Vader Error: You cannot use relative paths in ${e.data.file}. Use absolute paths instead. \n\n${a}`);c=c.replace(`href="${a}"`,`href="#${a}"`)}let d=Date.now()-a,$=!1;(r.includes("localhost")||r.includes("127.0.0.1")&&!$)&&($=!0,c+=`\${console.log('%c${e.data.name} component rendered in ${d}ms','color:#fff;background:#000;padding:5px;border-radius:5px;font-size:12px;font-weight:bold'),""}`);const h=c.split("<script>");h&&h.forEach(((e,a)=>{if(0===a)c=e;else{if(e.includes("// <![CDATA[ <-- For SVG support"))return;let a=e.split("<\/script>")[0];t+=a}}));let p=c.match(/(\$\(.*?\))/gs);if(p)for(;p.length;){let e=p.pop();c=c.replace(e,`\${${e.replace("$(","").replace(")","")}}`)}postMessage({template:`<div data-component=${e.data.name}>${c}</div>`,js:t||""})};
|
package/worker.js
CHANGED
|
@@ -3,6 +3,7 @@ onmessage = (e)=>{
|
|
|
3
3
|
let time_started = Date.now()
|
|
4
4
|
let strings = e.data.strings
|
|
5
5
|
let args = e.data.args
|
|
6
|
+
let js = ''
|
|
6
7
|
let l = e.data.location.split('/').slice(0,-1).join('/')
|
|
7
8
|
let result = "";
|
|
8
9
|
for (let i = 0; i < strings.length; i++) {
|
|
@@ -26,9 +27,12 @@ onmessage = (e)=>{
|
|
|
26
27
|
// Convert headings (e.g., #1-6 Heading => <h1-6>Heading</h1-6>)
|
|
27
28
|
// @ts-ignore
|
|
28
29
|
result = result.replace(/(#+)(.*)/g, (match, hashes, text) => {
|
|
29
|
-
|
|
30
|
+
console.log(match)
|
|
31
|
+
if(!match.includes('<') || !match.includes('>')){
|
|
30
32
|
let level = hashes.length;
|
|
31
|
-
|
|
33
|
+
return `<h ${level} class="markdown_heading">${text}</h${level}>`;
|
|
34
|
+
}else{
|
|
35
|
+
return match
|
|
32
36
|
}
|
|
33
37
|
});
|
|
34
38
|
|
|
@@ -62,7 +66,7 @@ onmessage = (e)=>{
|
|
|
62
66
|
result.split('\n').forEach((line, index, arr) => {
|
|
63
67
|
if (line.match(/^\s*-\s+(.*?)$/gm)) {
|
|
64
68
|
if (index === 0 || !arr[index - 1].match(/^\s*-\s+(.*?)$/gm)) {
|
|
65
|
-
result = result.replace(line, `<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside
|
|
69
|
+
result = result.replace(line, `<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li>`);
|
|
66
70
|
} else if (index === arr.length - 1 || !arr[index + 1].match(/^\s*-\s+(.*?)$/gm)) {
|
|
67
71
|
result = result.replace(line, `<li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li></ul>`);
|
|
68
72
|
} else {
|
|
@@ -70,8 +74,7 @@ onmessage = (e)=>{
|
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
});
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
|
|
75
78
|
// Convert ordered lists (e.g., 1. Item => <ol><li>Item</li></ol>) in order
|
|
76
79
|
|
|
77
80
|
result.split('\n').forEach((line, index, arr) => {
|
|
@@ -91,10 +94,30 @@ onmessage = (e)=>{
|
|
|
91
94
|
return `<li class="markdown_list_item">${text}</li>`;
|
|
92
95
|
});
|
|
93
96
|
result = result.replace(/^\s*---\s*$/gm, '<hr class="markdown_horizontal" />');
|
|
94
|
-
|
|
97
|
+
|
|
98
|
+
// Convert blockquotes (e.g., > Quote => <blockquote>Quote</blockquote>)
|
|
99
|
+
result = result.replace(/^\s*> (.*)$/gm, (match, text) => {
|
|
100
|
+
return `<blockquote class="markdown_blockquote">${text}</blockquote>`;
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Convert tables (e.g., | Header | Cell | => <table><thead><tr><th>Header</th><th>Cell</th></tr></thead></table>)
|
|
104
|
+
result = result.replace(/((?: *\|.*?)+)\n((?: *\|.*?)+)/gm, (match, header, cell) => {
|
|
105
|
+
const headerCells = header.split('|').slice(1, -1);
|
|
106
|
+
const cells = cell.split('|').slice(1, -1);
|
|
107
|
+
let table = '<table class="markdown_table">';
|
|
108
|
+
table += '<thead class="markdown_table_head"><tr class="markdown_table_row">';
|
|
109
|
+
headerCells.forEach((headerCell) => {
|
|
110
|
+
table += `<th class="markdown_table_header_cell">${headerCell}</th>`;
|
|
111
|
+
});
|
|
112
|
+
table += '</tr></thead><tbody class="markdown_table_body"><tr class="markdown_table_row">';
|
|
113
|
+
cells.forEach((cell) => {
|
|
114
|
+
table += `<td class="markdown_table_body_cell">${cell}</td>`;
|
|
115
|
+
});
|
|
116
|
+
table += '</tr></tbody></table>';
|
|
117
|
+
return table;
|
|
118
|
+
});
|
|
95
119
|
|
|
96
|
-
|
|
97
|
-
|
|
120
|
+
|
|
98
121
|
|
|
99
122
|
if(!result.includes('<body>')){
|
|
100
123
|
throw new Error(`Vader Error: You must enclose your html in a body tag for all components. \n\n${result}`)
|
|
@@ -168,6 +191,33 @@ onmessage = (e)=>{
|
|
|
168
191
|
}
|
|
169
192
|
|
|
170
193
|
|
|
171
|
-
|
|
194
|
+
const d = result.split('<script>')
|
|
195
|
+
|
|
196
|
+
if (d) {
|
|
197
|
+
d.forEach((scriptTag, index) => {
|
|
198
|
+
if (index === 0) {
|
|
199
|
+
result = scriptTag;
|
|
200
|
+
} else {
|
|
201
|
+
if(scriptTag.includes('// <![CDATA[ <-- For SVG support')){
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
let script = scriptTag.split('</script>')[0];
|
|
205
|
+
js += script;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let jstemplates = result.match(/(\$\(.*?\))/gs)
|
|
211
|
+
if(jstemplates){
|
|
212
|
+
while(jstemplates.length){
|
|
213
|
+
let jstemplate = jstemplates.pop()
|
|
214
|
+
// @ts-ignore
|
|
215
|
+
result = result.replace(jstemplate,`$\{${jstemplate.replace('$(','').replace(')','')}\}`)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
postMessage({
|
|
219
|
+
template: `<div data-component=${e.data.name}>${result}</div>`,
|
|
220
|
+
js: js ? js : ''
|
|
221
|
+
})
|
|
172
222
|
|
|
173
223
|
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// A launch configuration that launches the extension inside a new window
|
|
2
|
-
// Use IntelliSense to learn about possible attributes.
|
|
3
|
-
// Hover to view descriptions of existing attributes.
|
|
4
|
-
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
-
{
|
|
6
|
-
"version": "0.2.0",
|
|
7
|
-
"configurations": [
|
|
8
|
-
{
|
|
9
|
-
"name": "Extension",
|
|
10
|
-
"type": "extensionHost",
|
|
11
|
-
"request": "launch",
|
|
12
|
-
"args": [
|
|
13
|
-
"--extensionDevelopmentPath=${workspaceFolder}"
|
|
14
|
-
]
|
|
15
|
-
}
|
|
16
|
-
]
|
|
17
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# vader README
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
## Features
|
|
5
|
-
|
|
6
|
-
HTML syntax highlighting for vader files & intellisense / autocomplete for html elements and vader.js methods
|
|
7
|
-
|
|
8
|
-
Shows deprecated methods as deprecated in the intellisense - and shows suggestions for alternatives
|
|
9
|
-
|
|
10
|
-
## Requirements
|
|
11
|
-
|
|
12
|
-
Common knowlege of HTML and vader.js!
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## Known Issues
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
## Release Notes
|
|
20
|
-
|
|
21
|
-
Users appreciate release notes as you update your extension.
|
|
22
|
-
|
|
23
|
-
### 1.0.0
|
|
24
|
-
|
|
25
|
-
Initial release of vader
|
|
26
|
-
|