From 5b2807149f0021ef1a97cdf01c22d92c3a3eed0c Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 8 Mar 2023 11:59:37 +0100 Subject: [PATCH 01/40] Hosting: manual integrations via build contract --- dockerfiles/nginx/proxito.conf.template | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dockerfiles/nginx/proxito.conf.template b/dockerfiles/nginx/proxito.conf.template index 65ee44bb7c8..c00b5cfd3c7 100644 --- a/dockerfiles/nginx/proxito.conf.template +++ b/dockerfiles/nginx/proxito.conf.template @@ -88,6 +88,13 @@ server { proxy_hide_header Content-Security-Policy; set $content_security_policy $upstream_http_content_security_policy; add_header Content-Security-Policy $content_security_policy always; + + # Inject our own script dynamically + # TODO: decide where is the best place to do this + sub_filter '' '\n'; + # sub_filter_types text/html; + sub_filter_last_modified on; + sub_filter_once on; } # Serve 404 pages here From e18b40f6fe7c2c058bbf681063c1c577b5e8e9d3 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 8 Mar 2023 12:25:36 +0100 Subject: [PATCH 02/40] Use a single script to load everything --- dockerfiles/nginx/proxito.conf.template | 2 +- readthedocs/core/static/core/js/integrations.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 readthedocs/core/static/core/js/integrations.js diff --git a/dockerfiles/nginx/proxito.conf.template b/dockerfiles/nginx/proxito.conf.template index c00b5cfd3c7..ded61ac8f06 100644 --- a/dockerfiles/nginx/proxito.conf.template +++ b/dockerfiles/nginx/proxito.conf.template @@ -91,7 +91,7 @@ server { # Inject our own script dynamically # TODO: decide where is the best place to do this - sub_filter '' '\n'; + sub_filter '' '\n'; # sub_filter_types text/html; sub_filter_last_modified on; sub_filter_once on; diff --git a/readthedocs/core/static/core/js/integrations.js b/readthedocs/core/static/core/js/integrations.js new file mode 100644 index 00000000000..dd561bbeaf8 --- /dev/null +++ b/readthedocs/core/static/core/js/integrations.js @@ -0,0 +1,12 @@ +// Unique entry point that our servers will inject + +let link = document.createElement("link"); +link.setAttribute("rel", "stylesheet"); +link.setAttribute("type", "text/css"); +link.setAttribute("href", "/_/static/css/readthedocs-doc-embed.css"); +document.head.appendChild(link); + +let script = document.createElement("script"); +script.setAttribute("async", "async"); +script.setAttribute("src", "/_/static/javascript/readthedocs-doc-embed.js"); +document.head.appendChild(script); From 7754d5f98278561c04dcdbccad59390030b07980 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 8 Mar 2023 14:06:50 +0100 Subject: [PATCH 03/40] Include Read the Docs analytics to integrations --- readthedocs/core/static/core/js/integrations.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/readthedocs/core/static/core/js/integrations.js b/readthedocs/core/static/core/js/integrations.js index dd561bbeaf8..de9d6511075 100644 --- a/readthedocs/core/static/core/js/integrations.js +++ b/readthedocs/core/static/core/js/integrations.js @@ -6,7 +6,12 @@ link.setAttribute("type", "text/css"); link.setAttribute("href", "/_/static/css/readthedocs-doc-embed.css"); document.head.appendChild(link); -let script = document.createElement("script"); -script.setAttribute("async", "async"); -script.setAttribute("src", "/_/static/javascript/readthedocs-doc-embed.js"); -document.head.appendChild(script); +let embed = document.createElement("script"); +embed.setAttribute("async", "async"); +embed.setAttribute("src", "/_/static/javascript/readthedocs-doc-embed.js"); +document.head.appendChild(embed); + +let analytics = document.createElement("script"); +analytics.setAttribute("async", "async"); +analytics.setAttribute("src", "/_/static/javascript/readthedocs-analytics.js"); +document.head.appendChild(analytics); From 2925ed9acfff67e36a156341766247ac688f6ed1 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 8 Mar 2023 14:27:34 +0100 Subject: [PATCH 04/40] Initial work for hosting features --- readthedocs/core/static/core/js/integrations.js | 5 +++++ readthedocs/core/static/core/js/readthedocs-hosting.js | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 readthedocs/core/static/core/js/readthedocs-hosting.js diff --git a/readthedocs/core/static/core/js/integrations.js b/readthedocs/core/static/core/js/integrations.js index de9d6511075..9dcb717091b 100644 --- a/readthedocs/core/static/core/js/integrations.js +++ b/readthedocs/core/static/core/js/integrations.js @@ -15,3 +15,8 @@ let analytics = document.createElement("script"); analytics.setAttribute("async", "async"); analytics.setAttribute("src", "/_/static/javascript/readthedocs-analytics.js"); document.head.appendChild(analytics); + +let hosting = document.createElement("script"); +hosting.setAttribute("async", "async"); +hosting.setAttribute("src", "/_/static/core/js/readthedocs-hosting.js"); +document.head.appendChild(hosting); diff --git a/readthedocs/core/static/core/js/readthedocs-hosting.js b/readthedocs/core/static/core/js/readthedocs-hosting.js new file mode 100644 index 00000000000..777e0d528ef --- /dev/null +++ b/readthedocs/core/static/core/js/readthedocs-hosting.js @@ -0,0 +1,3 @@ +window.addEventListener("load", (event) => { + console.log("page is fully loaded"); +}); From 33856496dafdba1b1ae3f62e11b7e5cff2dd569a Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 8 Mar 2023 15:09:41 +0100 Subject: [PATCH 05/40] External version banner and doc-diff integration --- .../static/core/js/readthedocs-doc-diff.js | 1 + .../static/core/js/readthedocs-hosting.js | 34 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 readthedocs/core/static/core/js/readthedocs-doc-diff.js diff --git a/readthedocs/core/static/core/js/readthedocs-doc-diff.js b/readthedocs/core/static/core/js/readthedocs-doc-diff.js new file mode 100644 index 00000000000..0fceba340d4 --- /dev/null +++ b/readthedocs/core/static/core/js/readthedocs-doc-diff.js @@ -0,0 +1 @@ +(()=>{var e={416:(e,t,n)=>{"use strict";var r,i=n(224),o=n(52),a={addedClass:"doc-diff-added",modifiedClass:"doc-diff-modified",removedClass:"doc-diff-removed",skipModified:!0};function s(){var e={base_host:"",base_version:"latest",base_language:"en",base_page:"index.html",root_selector:"div.document[role='main']",inject_styles:!0};return new Promise((function(t,n){var r=document.querySelector("script#READTHEDOCS_DATA");if(r)try{var i=JSON.parse(r.innerText);e.base_host="https://"+i.project+".readthedocs.io",e.base_language=i.language,e.base_page=i.page+".html"}catch(e){console.debug("Error parsing configuration data",e)}var o=document.querySelector("script#doc-diff-config");if(o)try{var a=JSON.parse(o.innerText);Object.assign(e,a)}catch(e){console.debug("Error parsing configuration data",e)}return void 0===e.base_url&&(e.base_url=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"en",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"latest",r=arguments.length>3?arguments[3]:void 0,i=[];e&&(e="https://cors.writethedocs.workers.dev/corsproxy/?apiurl="+e);i=null==n&&null==t?[e,r]:null==t?[e,n,r]:[e,t,n,r];return i.join("/")}(e.base_host,e.base_language,e.base_version,e.base_page)),t(e)}))}e=n.hmd(e),n.c[n.s]!==e&&(r=new Promise((function(e){if("interactive"===document.readyState||"complete"===document.readyState)return e();document.addEventListener("DOMContentLoaded",(function(){e()}),{capture:!0,once:!0,passive:!0})})),new Promise((function(e){r.then((function(){return s()})).then((function(e){return function(e){return new Promise((function(t,n){fetch(e.base_url).then((function(e){return e.text()})).then((function(r){var s=(new DOMParser).parseFromString(r,"text/html").documentElement.querySelector(e.root_selector),f=document.querySelector(e.root_selector);null!=s&&null!=f||n(new Error("Element not found in both documents.")),e.inject_styles&&(document.adoptedStyleSheets=[o.Z]);var l=(0,i.visualDomDiff)(s,f,a);f.replaceWith(l.firstElementChild),t(!0)}))}))}(e)})).then((function(){e()})).catch((function(e){console.error(e.message)}))})))},52:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(81),i=n.n(r),o=n(645),a=n.n(o)()(i());a.push([e.id,".doc-diff-added {\n background-color: rgb(171, 242, 188);\n text-decoration: none;\n}\n\n.doc-diff-modified {\n}\n\n.doc-diff-removed {\n background-color: rgba(255, 129, 130, 0.4);\n text-decoration: none;\n}\n",""]);var s=new CSSStyleSheet;s.replaceSync(a.toString());const f=s},645:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n="",r=void 0!==t[5];return t[4]&&(n+="@supports (".concat(t[4],") {")),t[2]&&(n+="@media ".concat(t[2]," {")),r&&(n+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),n+=e(t),r&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,r,i,o){"string"==typeof e&&(e=[[null,e,void 0]]);var a={};if(r)for(var s=0;s0?" ".concat(h[5]):""," {").concat(h[1],"}")),h[5]=o),n&&(h[2]?(h[1]="@media ".concat(h[2]," {").concat(h[1],"}"),h[2]=n):h[2]=n),i&&(h[4]?(h[1]="@supports (".concat(h[4],") {").concat(h[1],"}"),h[4]=i):h[4]="".concat(i)),t.push(h))}},t}},81:e=>{"use strict";e.exports=function(e){return e[1]}},27:e=>{var t=function(){this.Diff_Timeout=1,this.Diff_EditCost=4,this.Match_Threshold=.5,this.Match_Distance=1e3,this.Patch_DeleteThreshold=.5,this.Patch_Margin=4,this.Match_MaxBits=32},n=-1;t.Diff=function(e,t){return[e,t]},t.prototype.diff_main=function(e,n,r,i){void 0===i&&(i=this.Diff_Timeout<=0?Number.MAX_VALUE:(new Date).getTime()+1e3*this.Diff_Timeout);var o=i;if(null==e||null==n)throw new Error("Null input. (diff_main)");if(e==n)return e?[new t.Diff(0,e)]:[];void 0===r&&(r=!0);var a=r,s=this.diff_commonPrefix(e,n),f=e.substring(0,s);e=e.substring(s),n=n.substring(s),s=this.diff_commonSuffix(e,n);var l=e.substring(e.length-s);e=e.substring(0,e.length-s),n=n.substring(0,n.length-s);var h=this.diff_compute_(e,n,a,o);return f&&h.unshift(new t.Diff(0,f)),l&&h.push(new t.Diff(0,l)),this.diff_cleanupMerge(h),h},t.prototype.diff_compute_=function(e,r,i,o){var a;if(!e)return[new t.Diff(1,r)];if(!r)return[new t.Diff(n,e)];var s=e.length>r.length?e:r,f=e.length>r.length?r:e,l=s.indexOf(f);if(-1!=l)return a=[new t.Diff(1,s.substring(0,l)),new t.Diff(0,f),new t.Diff(1,s.substring(l+f.length))],e.length>r.length&&(a[0][0]=a[2][0]=n),a;if(1==f.length)return[new t.Diff(n,e),new t.Diff(1,r)];var h=this.diff_halfMatch_(e,r);if(h){var u=h[0],c=h[1],d=h[2],g=h[3],p=h[4],v=this.diff_main(u,d,i,o),_=this.diff_main(c,g,i,o);return v.concat([new t.Diff(0,p)],_)}return i&&e.length>100&&r.length>100?this.diff_lineMode_(e,r,o):this.diff_bisect_(e,r,o)},t.prototype.diff_lineMode_=function(e,r,i){var o=this.diff_linesToChars_(e,r);e=o.chars1,r=o.chars2;var a=o.lineArray,s=this.diff_main(e,r,!1,i);this.diff_charsToLines_(s,a),this.diff_cleanupSemantic(s),s.push(new t.Diff(0,""));for(var f=0,l=0,h=0,u="",c="";f=1&&h>=1){s.splice(f-l-h,l+h),f=f-l-h;for(var d=this.diff_main(u,c,!1,i),g=d.length-1;g>=0;g--)s.splice(f,0,d[g]);f+=d.length}h=0,l=0,u="",c=""}f++}return s.pop(),s},t.prototype.diff_bisect_=function(e,r,i){for(var o=e.length,a=r.length,s=Math.ceil((o+a)/2),f=s,l=2*s,h=new Array(l),u=new Array(l),c=0;ci);m++){for(var y=-m+p;y<=m-v;y+=2){for(var w=f+y,x=(T=y==-m||y!=m&&h[w-1]o)v+=2;else if(x>a)p+=2;else if(g){if((M=f+d-y)>=0&&M=(N=o-u[M]))return this.diff_bisectSplit_(e,r,T,x,i)}}for(var D=-m+_;D<=m-b;D+=2){for(var N,M=f+D,E=(N=D==-m||D!=m&&u[M-1]o)b+=2;else if(E>a)_+=2;else if(!g){if((w=f+d-D)>=0&&w=(N=o-N))return this.diff_bisectSplit_(e,r,T,x,i)}}}}return[new t.Diff(n,e),new t.Diff(1,r)]},t.prototype.diff_bisectSplit_=function(e,t,n,r,i){var o=e.substring(0,n),a=t.substring(0,r),s=e.substring(n),f=t.substring(r),l=this.diff_main(o,a,!1,i),h=this.diff_main(s,f,!1,i);return l.concat(h)},t.prototype.diff_linesToChars_=function(e,t){var n=[],r={};function i(e){for(var t="",i=0,a=-1,s=n.length;ar?e=e.substring(n-r):nt.length?e:t,r=e.length>t.length?t:e;if(n.length<4||2*r.length=e.length?[r,o,a,s,h]:null}var a,s,f,l,h,u=o(n,r,Math.ceil(n.length/4)),c=o(n,r,Math.ceil(n.length/2));return u||c?(a=c?u&&u[4].length>c[4].length?u:c:u,e.length>t.length?(s=a[0],f=a[1],l=a[2],h=a[3]):(l=a[0],h=a[1],s=a[2],f=a[3]),[s,f,l,h,a[4]]):null},t.prototype.diff_cleanupSemantic=function(e){for(var r=!1,i=[],o=0,a=null,s=0,f=0,l=0,h=0,u=0;s0?i[o-1]:-1,f=0,l=0,h=0,u=0,a=null,r=!0)),s++;for(r&&this.diff_cleanupMerge(e),this.diff_cleanupSemanticLossless(e),s=1;s=p?(g>=c.length/2||g>=d.length/2)&&(e.splice(s,0,new t.Diff(0,d.substring(0,g))),e[s-1][1]=c.substring(0,c.length-g),e[s+1][1]=d.substring(g),s++):(p>=c.length/2||p>=d.length/2)&&(e.splice(s,0,new t.Diff(0,c.substring(0,p))),e[s-1][0]=1,e[s-1][1]=d.substring(0,d.length-p),e[s+1][0]=n,e[s+1][1]=c.substring(p),s++),s++}s++}},t.prototype.diff_cleanupSemanticLossless=function(e){function n(e,n){if(!e||!n)return 6;var r=e.charAt(e.length-1),i=n.charAt(0),o=r.match(t.nonAlphaNumericRegex_),a=i.match(t.nonAlphaNumericRegex_),s=o&&r.match(t.whitespaceRegex_),f=a&&i.match(t.whitespaceRegex_),l=s&&r.match(t.linebreakRegex_),h=f&&i.match(t.linebreakRegex_),u=l&&e.match(t.blanklineEndRegex_),c=h&&n.match(t.blanklineStartRegex_);return u||c?5:l||h?4:o&&!s&&f?3:s||f?2:o||a?1:0}for(var r=1;r=c&&(c=d,l=i,h=o,u=a)}e[r-1][1]!=l&&(l?e[r-1][1]=l:(e.splice(r-1,1),r--),e[r][1]=h,u?e[r+1][1]=u:(e.splice(r+1,1),r--))}r++}},t.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/,t.whitespaceRegex_=/\s/,t.linebreakRegex_=/[\r\n]/,t.blanklineEndRegex_=/\n\r?\n$/,t.blanklineStartRegex_=/^\r?\n\r?\n/,t.prototype.diff_cleanupEfficiency=function(e){for(var r=!1,i=[],o=0,a=null,s=0,f=!1,l=!1,h=!1,u=!1;s0?i[o-1]:-1,h=u=!1),r=!0)),s++;r&&this.diff_cleanupMerge(e)},t.prototype.diff_cleanupMerge=function(e){e.push(new t.Diff(0,""));for(var r,i=0,o=0,a=0,s="",f="";i1?(0!==o&&0!==a&&(0!==(r=this.diff_commonPrefix(f,s))&&(i-o-a>0&&0==e[i-o-a-1][0]?e[i-o-a-1][1]+=f.substring(0,r):(e.splice(0,0,new t.Diff(0,f.substring(0,r))),i++),f=f.substring(r),s=s.substring(r)),0!==(r=this.diff_commonSuffix(f,s))&&(e[i][1]=f.substring(f.length-r)+e[i][1],f=f.substring(0,f.length-r),s=s.substring(0,s.length-r))),i-=o+a,e.splice(i,o+a),s.length&&(e.splice(i,0,new t.Diff(n,s)),i++),f.length&&(e.splice(i,0,new t.Diff(1,f)),i++),i++):0!==i&&0==e[i-1][0]?(e[i-1][1]+=e[i][1],e.splice(i,1)):i++,a=0,o=0,s="",f=""}""===e[e.length-1][1]&&e.pop();var l=!1;for(i=1;it));r++)a=i,s=o;return e.length!=r&&e[r][0]===n?s:s+(t-a)},t.prototype.diff_prettyHtml=function(e){for(var t=[],r=/&/g,i=//g,a=/\n/g,s=0;s");switch(f){case 1:t[s]=''+l+"";break;case n:t[s]=''+l+"";break;case 0:t[s]=""+l+""}}return t.join("")},t.prototype.diff_text1=function(e){for(var t=[],n=0;nthis.Match_MaxBits)throw new Error("Pattern too long for this browser.");var r=this.match_alphabet_(t),i=this;function o(e,r){var o=e/t.length,a=Math.abs(n-r);return i.Match_Distance?o+a/i.Match_Distance:a?1:o}var a=this.Match_Threshold,s=e.indexOf(t,n);-1!=s&&(a=Math.min(o(0,s),a),-1!=(s=e.lastIndexOf(t,n+t.length))&&(a=Math.min(o(0,s),a)));var f,l,h=1<=g;_--){var b=r[e.charAt(_-1)];if(v[_]=0===d?(v[_+1]<<1|1)&b:(v[_+1]<<1|1)&b|(u[_+1]|u[_])<<1|1|u[_+1],v[_]&h){var m=o(d,_-1);if(m<=a){if(a=m,!((s=_-1)>n))break;g=Math.max(1,2*n-s)}}}if(o(d+1,n)>a)break;u=v}return s},t.prototype.match_alphabet_=function(e){for(var t={},n=0;n2&&(this.diff_cleanupSemantic(a),this.diff_cleanupEfficiency(a));else if(e&&"object"==typeof e&&void 0===r&&void 0===i)a=e,o=this.diff_text1(a);else if("string"==typeof e&&r&&"object"==typeof r&&void 0===i)o=e,a=r;else{if("string"!=typeof e||"string"!=typeof r||!i||"object"!=typeof i)throw new Error("Unknown call format to patch_make.");o=e,a=i}if(0===a.length)return[];for(var s=[],f=new t.patch_obj,l=0,h=0,u=0,c=o,d=o,g=0;g=2*this.Patch_Margin&&l&&(this.patch_addContext_(f,c),s.push(f),f=new t.patch_obj,l=0,c=d,h=u)}1!==p&&(h+=v.length),p!==n&&(u+=v.length)}return l&&(this.patch_addContext_(f,c),s.push(f)),s},t.prototype.patch_deepCopy=function(e){for(var n=[],r=0;rthis.Match_MaxBits?-1!=(s=this.match_main(t,h.substring(0,this.Match_MaxBits),l))&&(-1==(u=this.match_main(t,h.substring(h.length-this.Match_MaxBits),l+h.length-this.Match_MaxBits))||s>=u)&&(s=-1):s=this.match_main(t,h,l),-1==s)o[a]=!1,i-=e[a].length2-e[a].length1;else if(o[a]=!0,i=s-l,h==(f=-1==u?t.substring(s,s+h.length):t.substring(s,u+this.Match_MaxBits)))t=t.substring(0,s)+this.diff_text2(e[a].diffs)+t.substring(s+h.length);else{var c=this.diff_main(h,f,!1);if(h.length>this.Match_MaxBits&&this.diff_levenshtein(c)/h.length>this.Patch_DeleteThreshold)o[a]=!1;else{this.diff_cleanupSemanticLossless(c);for(var d,g=0,p=0;pa[0][1].length){var s=n-a[0][1].length;a[0][1]=r.substring(a[0][1].length)+a[0][1],o.start1-=s,o.start2-=s,o.length1+=s,o.length2+=s}if(0==(a=(o=e[e.length-1]).diffs).length||0!=a[a.length-1][0])a.push(new t.Diff(0,r)),o.length1+=n,o.length2+=n;else if(n>a[a.length-1][1].length){s=n-a[a.length-1][1].length;a[a.length-1][1]+=r.substring(0,s),o.length1+=s,o.length2+=s}return r},t.prototype.patch_splitMax=function(e){for(var r=this.Match_MaxBits,i=0;i2*r?(l.length1+=c.length,a+=c.length,h=!1,l.diffs.push(new t.Diff(u,c)),o.diffs.shift()):(c=c.substring(0,r-l.length1-this.Patch_Margin),l.length1+=c.length,a+=c.length,0===u?(l.length2+=c.length,s+=c.length):h=!1,l.diffs.push(new t.Diff(u,c)),c==o.diffs[0][1]?o.diffs.shift():o.diffs[0][1]=o.diffs[0][1].substring(c.length))}f=(f=this.diff_text2(l.diffs)).substring(f.length-this.Patch_Margin);var d=this.diff_text1(o.diffs).substring(0,this.Patch_Margin);""!==d&&(l.length1+=d.length,l.length2+=d.length,0!==l.diffs.length&&0===l.diffs[l.diffs.length-1][0]?l.diffs[l.diffs.length-1][1]+=d:l.diffs.push(new t.Diff(0,d))),h||e.splice(++i,0,l)}}},t.prototype.patch_toText=function(e){for(var t=[],n=0;n{"use strict";n.r(t),n.d(t,{__assign:()=>o,__asyncDelegator:()=>w,__asyncGenerator:()=>y,__asyncValues:()=>x,__await:()=>m,__awaiter:()=>h,__classPrivateFieldGet:()=>T,__classPrivateFieldIn:()=>O,__classPrivateFieldSet:()=>S,__createBinding:()=>c,__decorate:()=>s,__exportStar:()=>d,__extends:()=>i,__generator:()=>u,__importDefault:()=>E,__importStar:()=>M,__makeTemplateObject:()=>D,__metadata:()=>l,__param:()=>f,__read:()=>p,__rest:()=>a,__spread:()=>v,__spreadArray:()=>b,__spreadArrays:()=>_,__values:()=>g});var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},r(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var o=function(){return o=Object.assign||function(e){for(var t,n=1,r=arguments.length;n=0;s--)(i=e[s])&&(a=(o<3?i(a):o>3?i(t,n,a):i(t,n))||a);return o>3&&a&&Object.defineProperty(t,n,a),a}function f(e,t){return function(n,r){t(n,r,e)}}function l(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}function h(e,t,n,r){return new(n||(n=Promise))((function(i,o){function a(e){try{f(r.next(e))}catch(e){o(e)}}function s(e){try{f(r.throw(e))}catch(e){o(e)}}function f(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}f((r=r.apply(e,t||[])).next())}))}function u(e,t){var n,r,i,o,a={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function s(o){return function(s){return function(o){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(i=2&o[0]?r.return:o[0]?r.throw||((i=r.return)&&i.call(r),0):r.next)&&!(i=i.call(r,o[1])).done)return i;switch(r=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return a.label++,{value:o[1],done:!1};case 5:a.label++,r=o[1],o=[0];continue;case 7:o=a.ops.pop(),a.trys.pop();continue;default:if(!(i=a.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function p(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,i,o=n.call(e),a=[];try{for(;(void 0===t||t-- >0)&&!(r=o.next()).done;)a.push(r.value)}catch(e){i={error:e}}finally{try{r&&!r.done&&(n=o.return)&&n.call(o)}finally{if(i)throw i.error}}return a}function v(){for(var e=[],t=0;t1||s(e,t)}))})}function s(e,t){try{(n=i[e](t)).value instanceof m?Promise.resolve(n.value.v).then(f,l):h(o[0][2],n)}catch(e){h(o[0][3],e)}var n}function f(e){s("next",e)}function l(e){s("throw",e)}function h(e,t){e(t),o.shift(),o.length&&s(o[0][0],o[0][1])}}function w(e){var t,n;return t={},r("next"),r("throw",(function(e){throw e})),r("return"),t[Symbol.iterator]=function(){return this},t;function r(r,i){t[r]=e[r]?function(t){return(n=!n)?{value:m(e[r](t)),done:"return"===r}:i?i(t):t}:i}}function x(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e=g(e),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(n){t[n]=e[n]&&function(t){return new Promise((function(r,i){(function(e,t,n,r){Promise.resolve(r).then((function(t){e({value:t,done:n})}),t)})(r,i,(t=e[n](t)).done,t.value)}))}}}function D(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e}var N=Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t};function M(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&c(t,e,n);return N(t,e),t}function E(e){return e&&e.__esModule?e:{default:e}}function T(e,t,n,r){if("a"===n&&!r)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?r:"a"===n?r.call(e):r?r.value:t.get(e)}function S(e,t,n,r,i){if("m"===r)throw new TypeError("Private method is not writable");if("a"===r&&!i)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!i:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===r?i.call(e,n):i?i.value=n:t.set(e,n),n}function O(e,t){if(null===t||"object"!=typeof t&&"function"!=typeof t)throw new TypeError("Cannot use 'in' operator on non-object");return"function"==typeof e?t===e:e.has(t)}},967:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(402),i=new Set;i.add("IMG"),i.add("VIDEO"),i.add("IFRAME"),i.add("OBJECT"),i.add("SVG");var o=new Set;o.add("BDO"),o.add("BDI"),o.add("Q"),o.add("CITE"),o.add("CODE"),o.add("DATA"),o.add("TIME"),o.add("VAR"),o.add("DFN"),o.add("ABBR"),o.add("STRONG"),o.add("EM"),o.add("BIG"),o.add("SMALL"),o.add("MARK"),o.add("SUB"),o.add("SUP"),o.add("SAMP"),o.add("KBD"),o.add("B"),o.add("I"),o.add("S"),o.add("U"),o.add("SPAN"),t.optionsToConfig=function(e){var t=void 0===e?{}:e,n=t.addedClass,a=void 0===n?"vdd-added":n,s=t.modifiedClass,f=void 0===s?"vdd-modified":s,l=t.removedClass,h=void 0===l?"vdd-removed":l,u=t.skipModified,c=void 0!==u&&u,d=t.skipChildren,g=t.skipSelf,p=t.diffText;return{addedClass:a,diffText:void 0===p?r.diffText:p,modifiedClass:f,removedClass:h,skipModified:c,skipChildren:function(e){if(!r.isElement(e)&&!r.isDocumentFragment(e)&&!r.isDocument(e))return!0;if(d){var t=d(e);if("boolean"==typeof t)return t}return i.has(e.nodeName)},skipSelf:function(e){if(!r.isText(e)&&!r.isElement(e))return!0;if(g){var t=g(e);if("boolean"==typeof t)return t}return o.has(e.nodeName)}}}},145:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(27),i=n(967),o=n(844),a=n(402),s=function(e){return"TH"===e?"TD":e},f=function(e,t){return new o.DomIterator(e,t).reduce((function(e,t){return e+(a.isText(t)?t.data:a.charForNodeName(s(t.nodeName)))}),"")},l=function(e){return a.isText(e)?e.length:1},h=function(e){return"TR"===e.nodeName},u={skipChildren:h,skipSelf:function(e){return!h(e)}};t.visualDomDiff=function e(t,n,h){var c,d;void 0===h&&(h={});var g,p,v,_,b,m=n.ownerDocument||n,y=i.optionsToConfig(h),w=y.addedClass,x=y.diffText,D=y.modifiedClass,N=y.removedClass,M=y.skipSelf,E=y.skipChildren,T=function(e){return!M(e)},S=function(e,t){return a.getAncestors(e,t).filter(T).length},O=function(e){return a.isElement(e)&&M(e)},A=function(e,t){return a.getAncestors(e,t).filter(O).reverse()},C=function(e){return Z.has(e)?1:J.has(e)?-1:0},P=x(f(t,y),f(n,y)),k=0,I=new o.DomIterator(t,y),j=new o.DomIterator(n,y),F=0,R=0,B=0;v=P[k++],c=I.next(),g=c.done,_=c.value,d=j.next(),p=d.done,b=d.value;var L=m.createDocumentFragment(),U=L,q=0,Q=L,V=0,G=null,H=null,J=new Set,Z=new Set,$=new Set,z=new Map,K=new Array,X=new Map;function Y(){for(var e=S(_,t);q>e;){if(!U.parentNode)return a.never();U===G&&(G=null),U=U.parentNode,q--}if(q!==e)return a.never()}function W(){for(var e=S(b,n);V>e;){if(!Q.parentNode)return a.never();Q===H&&(H=null),Q=Q.parentNode,V--}if(V!==e)return a.never()}function ee(e){if(U!==Q||H||G)return a.never();if(a.isText(e)){var r=A(_,t),i=A(b,n);z.set(e,i);var o=r.length;if(o!==i.length)$.add(e);else for(var s=0;st)return a.never()}function ie(e){var t,n=l(_);if((R+=e)===n)t=I.next(),g=t.done,_=t.value,R=0;else if(R>n)return a.never()}function oe(e){var t,n=l(b);if((B+=e)===n)t=j.next(),p=t.done,b=t.value,B=0;else if(B>n)return a.never()}for(;v;)if(v[0]===r.DIFF_DELETE){if(g)return a.never();Y();var ae=Math.min(v[1].length-F,l(_)-R),se=v[1].substring(F,F+ae);te(a.isText(_)?m.createTextNode(se):_.cloneNode(!1)),re(ae),ie(ae)}else if(v[0]===r.DIFF_INSERT){if(p)return a.never();W();var fe=Math.min(v[1].length-F,l(b)-B);se=v[1].substring(F,F+fe);ne(a.isText(b)?m.createTextNode(se):b.cloneNode(!1)),re(fe),oe(fe)}else{if(g||p)return a.never();Y(),W();var le=Math.min(v[1].length-F,l(_)-R,l(b)-B);se=v[1].substring(F,F+le);U===Q&&(a.isText(_)&&a.isText(b)||s(_.nodeName)===s(b.nodeName)&&!E(_)&&!E(b)||a.areNodesEqual(_,b))?ee(a.isText(b)?m.createTextNode(se):b.cloneNode(!1)):(te(a.isText(_)?m.createTextNode(se):_.cloneNode(!1)),ne(a.isText(b)?m.createTextNode(se):b.cloneNode(!1))),re(le),ie(le),oe(le)}return J.forEach((function(e){for(var t=e.parentNode,n=e.previousSibling;n&&Z.has(n);)t.insertBefore(e,n),n=e.previousSibling})),K.forEach((function(t){var n=t.newTable,r=t.oldTable,i=t.outputTable;if(!a.isTableValid(r,!0)||!a.isTableValid(n,!0)||!a.isTableValid(i,!1)){new o.DomIterator(i).forEach((function(e){Z.delete(e),J.delete(e),$.delete(e),z.delete(e)}));var s=i.parentNode,f=r.cloneNode(!0),l=n.cloneNode(!0);return s.insertBefore(f,i),s.insertBefore(l,i),s.removeChild(i),J.add(f),void Z.add(l)}var c=[];new o.DomIterator(i,u).some((function(e){var t=X.get(e);if(!t)return!1;var n=t.oldRow,r=t.newRow,i=n.childNodes.length,o=r.childNodes.length,a=Math.max(i,o),s=Math.min(i,o);if(e.childNodes.length===a)for(var f=e.childNodes,l=0,h=f.length;l{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e,t){this.rootNode=e,this.config=t,this.descend=!0,this.nextNode=this.rootNode,this.skipSelf(this.nextNode)&&this.next()}return e.prototype.toArray=function(){for(var e,t=[],n=this.next(),r=n.done,i=n.value;!r;)t.push(i),r=(e=this.next()).done,i=e.value;return t},e.prototype.forEach=function(e){for(var t,n=this.next(),r=n.done,i=n.value;!r;)e(i),r=(t=this.next()).done,i=t.value},e.prototype.reduce=function(e,t){for(var n,r=t,i=this.next(),o=i.done,a=i.value;!o;)r=e(r,a),o=(n=this.next()).done,a=n.value;return r},e.prototype.some=function(e){for(var t,n=this.next(),r=n.done,i=n.value;!r;){if(e(i))return!0;r=(t=this.next()).done,i=t.value}return!1},e.prototype.next=function(){if(!this.nextNode)return{done:!0,value:this.rootNode};var e=this.nextNode;return this.descend&&this.nextNode.firstChild&&!this.skipChildren(this.nextNode)?this.nextNode=this.nextNode.firstChild:this.nextNode===this.rootNode?this.nextNode=null:this.nextNode.nextSibling?(this.nextNode=this.nextNode.nextSibling,this.descend=!0):(this.nextNode=this.nextNode.parentNode,this.descend=!1,this.next()),this.nextNode&&this.skipSelf(this.nextNode)&&this.next(),{done:!1,value:e}},e.prototype.skipSelf=function(e){return!(!this.config||!this.config.skipSelf)&&this.config.skipSelf(e)},e.prototype.skipChildren=function(e){return!(!this.config||!this.config.skipChildren)&&this.config.skipChildren(e)},e}();t.DomIterator=n},224:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(655).__exportStar(n(145),t)},402:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(27);function i(e){return e.nodeType===e.ELEMENT_NODE}function o(e){return e.nodeType===e.TEXT_NODE}function a(e){return e.nodeType===e.COMMENT_NODE}function s(e,t){return e===t}function f(e,t,n){if(void 0===n&&(n=s),e.length!==t.length)return!1;for(var r=0,i=e.length;r="豈"?t++:(n[1]=a.substring(0,a.length-1),i[1]=l+s.substring(0,s.length-1),o[1]=l+f,0===n[1].length&&e.splice(t,1))}else t++}}t.isElement=i,t.isText=o,t.isDocument=function(e){return e.nodeType===e.DOCUMENT_NODE},t.isDocumentFragment=function(e){return e.nodeType===e.DOCUMENT_FRAGMENT_NODE},t.isComment=a,t.strictEqual=s,t.areArraysEqual=f,t.areNodesEqual=function e(t,n,r){if(void 0===r&&(r=!1),t===n)return!0;if(t.nodeType!==n.nodeType||t.nodeName!==n.nodeName)return!1;if(o(t)||a(t)){if(t.data!==n.data)return!1}else if(i(t)){var s=l(t).sort();if(!f(s,l(n).sort()))return!1;for(var h=0,u=s.length;h0&&o.push([r.DIFF_EQUAL,l.substring(0,g)]),c.diff_cleanupSemantic(o),d(i,o),o.length=0,i.push([r.DIFF_EQUAL,l.substring(g,h-p)]),p>0&&o.push([r.DIFF_EQUAL,l.substring(h-p)])}else o.push(f)}else o.push(f)}return c.diff_cleanupSemantic(o),d(i,o),o.length=0,c.diff_cleanupMerge(i),u(i),i},t.markUpNode=function(e,t,n){var r=e.ownerDocument,o=e.parentNode,a=e.previousSibling;if(i(e))e.classList.add(n);else if(a&&a.nodeName===t&&a.classList.contains(n))a.appendChild(e);else{var s=r.createElement(t);s.classList.add(n),o.insertBefore(s,e),s.appendChild(e)}},t.isTableValid=function(e,t){var n;return function(e){var t=e.childNodes,n=t.length,i=0;i{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:()=>{throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};n(n.s=416)})(); \ No newline at end of file diff --git a/readthedocs/core/static/core/js/readthedocs-hosting.js b/readthedocs/core/static/core/js/readthedocs-hosting.js index 777e0d528ef..89514a24dd0 100644 --- a/readthedocs/core/static/core/js/readthedocs-hosting.js +++ b/readthedocs/core/static/core/js/readthedocs-hosting.js @@ -1,3 +1,35 @@ +function injectExternalVersionWarning() { + let admonition = ` +
+

Warning

+

+ This page + was created + from a pull request + (#${ READTHEDOCS_DATA.version }). +

+
+`; + + let main = document.querySelector('[role=main]'); + let node = document.createElement("div"); + node.innerHTML = admonition; + main.insertBefore(node, main.firstChild); +} + +function injectDocDiff() { + let docdiff = document.createElement("script"); + docdiff.setAttribute("async", "async"); + docdiff.setAttribute("src", "/_/static/core/js/readthedocs-doc-diff.js"); + document.head.appendChild(docdiff); +} + window.addEventListener("load", (event) => { - console.log("page is fully loaded"); + if (READTHEDOCS_DATA.build.external_version === true) { + injectExternalVersionWarning(); + + if (READTHEDOCS_DATA.features.docdiff.enabled === true) { + injectDocDiff(); + } + } }); From 1e391b820c2b45504419b9affe00f7592dd09a32 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 8 Mar 2023 15:15:25 +0100 Subject: [PATCH 06/40] Old version warning --- .../static/core/js/readthedocs-hosting.js | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/readthedocs/core/static/core/js/readthedocs-hosting.js b/readthedocs/core/static/core/js/readthedocs-hosting.js index 89514a24dd0..8ff7d1bf6a5 100644 --- a/readthedocs/core/static/core/js/readthedocs-hosting.js +++ b/readthedocs/core/static/core/js/readthedocs-hosting.js @@ -4,7 +4,7 @@ function injectExternalVersionWarning() {

Warning

This page - was created + was created from a pull request (#${ READTHEDOCS_DATA.version }).

@@ -24,6 +24,27 @@ function injectDocDiff() { document.head.appendChild(docdiff); } +function injectOldVersionWarning() { + // TODO: compute if the user is reading the latest version or not before showing the warning. + let admonition = ` +
+

Warning

+

+ This page documents version + ${ READTHEDOCS_DATA.version }. + The latest version is + ${ READTHEDOCS_DATA.version }. +

+
+`; + + let main = document.querySelector('[role=main]'); + let node = document.createElement("div"); + node.innerHTML = admonition; + main.insertBefore(node, main.firstChild); +} + + window.addEventListener("load", (event) => { if (READTHEDOCS_DATA.build.external_version === true) { injectExternalVersionWarning(); @@ -32,4 +53,5 @@ window.addEventListener("load", (event) => { injectDocDiff(); } } + injectOldVersionWarning(); }); From 6afca0b7d84f6f7377bb981c45a03f422efb810f Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 8 Mar 2023 15:58:56 +0100 Subject: [PATCH 07/40] Do not inject doc-diff on search page --- readthedocs/core/static/core/js/readthedocs-hosting.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readthedocs/core/static/core/js/readthedocs-hosting.js b/readthedocs/core/static/core/js/readthedocs-hosting.js index 8ff7d1bf6a5..5ba24024786 100644 --- a/readthedocs/core/static/core/js/readthedocs-hosting.js +++ b/readthedocs/core/static/core/js/readthedocs-hosting.js @@ -50,7 +50,10 @@ window.addEventListener("load", (event) => { injectExternalVersionWarning(); if (READTHEDOCS_DATA.features.docdiff.enabled === true) { - injectDocDiff(); + if(!window.location.pathname.endsWith("search.html")) { + // Avoid injecting doc-diff on search page because it doesn't make sense + injectDocDiff(); + } } } injectOldVersionWarning(); From 7ce98a4d4f34a4c1845dc6e3e0e5112af7c39b0c Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 8 Mar 2023 16:00:00 +0100 Subject: [PATCH 08/40] Inject old version warning only for non-external versions --- readthedocs/core/static/core/js/readthedocs-hosting.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readthedocs/core/static/core/js/readthedocs-hosting.js b/readthedocs/core/static/core/js/readthedocs-hosting.js index 5ba24024786..9397aa03045 100644 --- a/readthedocs/core/static/core/js/readthedocs-hosting.js +++ b/readthedocs/core/static/core/js/readthedocs-hosting.js @@ -56,5 +56,8 @@ window.addEventListener("load", (event) => { } } } - injectOldVersionWarning(); + else { + // Inject old version warning only for non-external versions + injectOldVersionWarning(); + } }); From 3ca96ec2f36669792797b8327e693155a9f3b396 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 8 Mar 2023 16:44:38 +0100 Subject: [PATCH 09/40] Comments! --- readthedocs/core/static/core/js/integrations.js | 4 ++++ .../core/static/core/js/readthedocs-hosting.js | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/readthedocs/core/static/core/js/integrations.js b/readthedocs/core/static/core/js/integrations.js index 9dcb717091b..16e517eed64 100644 --- a/readthedocs/core/static/core/js/integrations.js +++ b/readthedocs/core/static/core/js/integrations.js @@ -20,3 +20,7 @@ let hosting = document.createElement("script"); hosting.setAttribute("async", "async"); hosting.setAttribute("src", "/_/static/core/js/readthedocs-hosting.js"); document.head.appendChild(hosting); + +// TODO: insert search-as-you-type once it becomes a JS library +// decoupled from Sphinx. +// See https://github.com/readthedocs/readthedocs-sphinx-search/issues/67 diff --git a/readthedocs/core/static/core/js/readthedocs-hosting.js b/readthedocs/core/static/core/js/readthedocs-hosting.js index 9397aa03045..44e32263922 100644 --- a/readthedocs/core/static/core/js/readthedocs-hosting.js +++ b/readthedocs/core/static/core/js/readthedocs-hosting.js @@ -1,4 +1,6 @@ function injectExternalVersionWarning() { + // TODO: make all these banners (injected HTML) templates that users can override with their own. + // This way, we allow customization of the look&feel without compromising the logic. let admonition = `

Warning

@@ -38,6 +40,8 @@ function injectOldVersionWarning() {
`; + // Borrowed and adapted from: + // https://github.com/readthedocs/readthedocs.org/blob/7ce98a4d4f34a4c1845dc6e3e0e5112af7c39b0c/readthedocs/core/static-src/core/js/doc-embed/version-compare.js#L1 let main = document.querySelector('[role=main]'); let node = document.createElement("div"); node.innerHTML = admonition; @@ -46,6 +50,9 @@ function injectOldVersionWarning() { window.addEventListener("load", (event) => { + // TODO: use the proxied API here + // "repository_url" could be retrived using the API, but there are some CORS issues and design decisions + // that it's probably smart to avoid and just rely on a fixed value from the build output :) if (READTHEDOCS_DATA.build.external_version === true) { injectExternalVersionWarning(); @@ -57,6 +64,11 @@ window.addEventListener("load", (event) => { } } else { + // TODO: there some data we need from `/api/v2/footer_html/`, + // like `is_highest` and `show_version_warning`. + // However, this call is happening inside the `readthedocs-doc-embed.js`. + // We could make the call again here for now as demo, + // but it would be good to refactor that code // Inject old version warning only for non-external versions injectOldVersionWarning(); } From f4f12681396d5cd97ea75d8b8da72b6e48ceabe5 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 8 Mar 2023 20:02:01 +0100 Subject: [PATCH 10/40] More comments --- readthedocs/core/static/core/js/integrations.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/readthedocs/core/static/core/js/integrations.js b/readthedocs/core/static/core/js/integrations.js index 16e517eed64..d9772af1568 100644 --- a/readthedocs/core/static/core/js/integrations.js +++ b/readthedocs/core/static/core/js/integrations.js @@ -1,5 +1,8 @@ // Unique entry point that our servers will inject +// TODO: use `READTHEDOCS_DATA.features.hosting.version` to decide +// what version of these Javascript libraries we need to inject here. +// See https://github.com/readthedocs/readthedocs.org/issues/9063#issuecomment-1325483505 let link = document.createElement("link"); link.setAttribute("rel", "stylesheet"); link.setAttribute("type", "text/css"); @@ -24,3 +27,7 @@ document.head.appendChild(hosting); // TODO: insert search-as-you-type once it becomes a JS library // decoupled from Sphinx. // See https://github.com/readthedocs/readthedocs-sphinx-search/issues/67 + +// TODO: find a way to remove the Sphinx default search, since it duplicates the results sometimes. +// This removal is currently happening at our Sphinx extension: +// https://github.com/readthedocs/readthedocs-sphinx-ext/blob/7cc1e60f7dcdeb7af35e3479509a621d5bac0976/readthedocs_ext/readthedocs.py#L239 From a5965129c61b9bcdff2f2098ff7ce7f8c093dc74 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Thu, 9 Mar 2023 11:40:45 +0100 Subject: [PATCH 11/40] Build: pass `PATH` environment variable to Docker container Instead of prepending all the commands with the `PATH=` variable, we pass the environment variable directly to the Docker container. This allow us to run multi-line shell script without failing with weird syntax errors. Besides, the implementation is cleaner since all the environment variables are passed to the commands in the same way. I added some _default paths_ that I found by checking the local Docker container. I'm also passing the users' path, depending if we are working locally as root or in production. This is not 100% complete and there may be some other issues that I'm not seeing yet, but I think it's a first step to behave in a way our users are expecting. Closes #10103 --- readthedocs/doc_builder/environments.py | 69 ++++++++++++++----------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/readthedocs/doc_builder/environments.py b/readthedocs/doc_builder/environments.py index e10447b2b16..9e59e7d28cc 100644 --- a/readthedocs/doc_builder/environments.py +++ b/readthedocs/doc_builder/environments.py @@ -10,13 +10,13 @@ import structlog from django.conf import settings from django.utils.translation import gettext_lazy as _ -from docker import APIClient from docker.errors import APIError as DockerAPIError from docker.errors import DockerException from docker.errors import NotFound as DockerNotFoundError -from requests.exceptions import ConnectionError, ReadTimeout +from requests.exceptions import ConnectionError, ReadTimeout # noqa from requests_toolbelt.multipart.encoder import MultipartEncoder +from docker import APIClient from readthedocs.api.v2.client import api as api_v2 from readthedocs.builds.models import BuildCommandResultMixin from readthedocs.core.utils import slugify @@ -73,7 +73,7 @@ def __init__( bin_path=None, record_as_success=False, demux=False, - **kwargs, + **kwargs, # pylint: disable=unused-argument ): self.command = command self.shell = shell @@ -252,8 +252,8 @@ def save(self): {key: str(value) for key, value in data.items()} ) resource = api_v2.command - resp = resource._store['session'].post( - resource._store['base_url'] + '/', + resp = resource._store["session"].post( # pylint: disable=protected-access + resource._store["base_url"] + "/", # pylint: disable=protected-access data=encoder, headers={ 'Content-Type': encoder.content_type, @@ -301,11 +301,35 @@ def run(self): self.start_time = datetime.utcnow() client = self.build_env.get_client() + + # Create a copy of the environment to update PATH variable + environment = self._environment.copy() + # Default PATH variable + environment[ + "PATH" + ] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + # Add asdf extra paths + environment["PATH"] += ( + ":/home/{settings.RTD_DOCKER_USER}/.asdf/shims" + ":/home/{settings.RTD_DOCKER_USER}/.asdf/bin" + ) + + if settings.RTD_DOCKER_COMPOSE: + environment["PATH"] += ":/root/.asdf/shims:/root/.asdf/bin" + + # Prepend the BIN_PATH if it's defined + if self.bin_path: + path = environment.get("PATH") + bin_path = self._escape_command(self.bin_path) + environment["PATH"] = bin_path + if path: + environment["PATH"] += f":{path}" + try: exec_cmd = client.exec_create( container=self.build_env.container_id, cmd=self.get_wrapped_command(), - environment=self._environment, + environment=environment, user=self.user, workdir=self.cwd, stdout=True, @@ -357,31 +381,18 @@ def get_wrapped_command(self): """ Wrap command in a shell and optionally escape special bash characters. - In order to set the current working path inside a docker container, we - need to wrap the command in a shell call manually. - Some characters will be interpreted as shell characters without escaping, such as: ``pip install requests<0.8``. When passing ``escape_command=True`` in the init method this escapes a good majority of those characters. """ - prefix = '' - if self.bin_path: - bin_path = self._escape_command(self.bin_path) - prefix += f'PATH={bin_path}:$PATH ' - command = ( ' '.join( self._escape_command(part) if self.escape_command else part for part in self.command ) ) - return ( - "/bin/sh -c '{prefix}{cmd}'".format( - prefix=prefix, - cmd=command, - ) - ) + return f"/bin/bash -c '{command}'" def _escape_command(self, cmd): r"""Escape the command by prefixing suspicious chars with `\`.""" @@ -524,14 +535,14 @@ class BuildEnvironment(BaseEnvironment): """ def __init__( - self, - project=None, - version=None, - build=None, - config=None, - environment=None, - record=True, - **kwargs, + self, + project=None, + version=None, + build=None, + config=None, + environment=None, + record=True, + **kwargs, # pylint: disable=unused-argument ): super().__init__(project, environment) self.version = version @@ -557,7 +568,7 @@ def run(self, *cmd, **kwargs): }) return super().run(*cmd, **kwargs) - def run_command_class(self, *cmd, **kwargs): # pylint: disable=arguments-differ + def run_command_class(self, *cmd, **kwargs): # pylint: disable=signature-differs kwargs.update({ 'build_env': self, }) From 33fdb2b30f6906847b8af6d410b20f5087ee275a Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Thu, 9 Mar 2023 12:09:42 +0100 Subject: [PATCH 12/40] Lint: for some reason fails at CircleCI otherwise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Locally it tries to reverted back 🤷 --- readthedocs/doc_builder/environments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/doc_builder/environments.py b/readthedocs/doc_builder/environments.py index 9e59e7d28cc..a54919f4749 100644 --- a/readthedocs/doc_builder/environments.py +++ b/readthedocs/doc_builder/environments.py @@ -10,13 +10,13 @@ import structlog from django.conf import settings from django.utils.translation import gettext_lazy as _ +from docker import APIClient from docker.errors import APIError as DockerAPIError from docker.errors import DockerException from docker.errors import NotFound as DockerNotFoundError from requests.exceptions import ConnectionError, ReadTimeout # noqa from requests_toolbelt.multipart.encoder import MultipartEncoder -from docker import APIClient from readthedocs.api.v2.client import api as api_v2 from readthedocs.builds.models import BuildCommandResultMixin from readthedocs.core.utils import slugify From ea2af4c4556d2a731061799d0ccb7e8dd3898ef7 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Fri, 10 Mar 2023 18:00:51 +0100 Subject: [PATCH 13/40] Feature flag for new hosting integrations X-RTD-Hosting-Integration: true/false This can be used from CloudFlare to decide whether or not inject a `\n'; diff --git a/readthedocs/projects/models.py b/readthedocs/projects/models.py index bf502c1fce5..6613a649145 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -1884,6 +1884,7 @@ def add_features(sender, **kwargs): CANCEL_OLD_BUILDS = "cancel_old_builds" DONT_CREATE_INDEX = "dont_create_index" USE_RCLONE = "use_rclone" + HOSTING_INTEGRATIONS = "hosting_integrations" FEATURES = ( (ALLOW_DEPRECATED_WEBHOOKS, _('Allow deprecated webhook views')), @@ -2058,6 +2059,10 @@ def add_features(sender, **kwargs): USE_RCLONE, _("Use rclone for syncing files to the media storage."), ), + ( + HOSTING_INTEGRATIONS, + _("Inject 'integrations.js' as \n'; + sub_filter '' '\n'; # sub_filter_types text/html; sub_filter_last_modified on; sub_filter_once on; diff --git a/readthedocs/core/static/core/js/readthedocs-client.js b/readthedocs/core/static/core/js/readthedocs-client.js new file mode 100644 index 00000000000..80a764ba889 --- /dev/null +++ b/readthedocs/core/static/core/js/readthedocs-client.js @@ -0,0 +1 @@ +(()=>{"use strict";!function(){const e=new Promise((e=>{if("interactive"===document.readyState||"complete"===document.readyState)return e();document.addEventListener("DOMContentLoaded",(()=>{e()}),{capture:!0,once:!0,passive:!0})}));new Promise((n=>{e.then((()=>fetch("/_/readthedocs-config.json",{method:"GET"}).then((e=>{if(e.ok)return e.json();console.debug("Error parsing configuration data")})))).then((e=>function(e){return new Promise(((n,r)=>{let t=`\n
\n

Warning

\n

\n This page\n was created \n from a pull request\n (#${e.version.slug}).\n

\n
\n`,o=document.querySelector("[role=main]")||document.querySelector("#main"),i=document.createElement("div");i.innerHTML=t,o.insertBefore(i,o.firstChild)}))}(e))).then((()=>{n()})).catch((e=>{console.error(e.message)}))}))}()})(); diff --git a/readthedocs/proxito/urls.py b/readthedocs/proxito/urls.py index 43ac7119aed..a1d70c4ef80 100644 --- a/readthedocs/proxito/urls.py +++ b/readthedocs/proxito/urls.py @@ -40,6 +40,7 @@ from readthedocs.constants import pattern_opts from readthedocs.core.views import HealthCheckView from readthedocs.projects.views.public import ProjectDownloadMedia +from readthedocs.proxito.views.hosting import ReadTheDocsConfigJson from readthedocs.proxito.views.serve import ( ServeDocs, ServeError404, @@ -114,6 +115,12 @@ ServeStaticFiles.as_view(), name="proxito_static_files", ), + # readthedocs-config.js + path( + f"{DOC_PATH_PREFIX}readthedocs-config.json", + ReadTheDocsConfigJson.as_view(), + name="proxito_readthedocs_config_json", + ), ] core_urls = [ diff --git a/readthedocs/proxito/views/hosting.py b/readthedocs/proxito/views/hosting.py new file mode 100644 index 00000000000..7882111796d --- /dev/null +++ b/readthedocs/proxito/views/hosting.py @@ -0,0 +1,40 @@ +"""Views for hosting features.""" + +import structlog +from django.conf import settings +from django.http import JsonResponse +from django.views import View + +from readthedocs.core.mixins import CDNCacheControlMixin + +log = structlog.get_logger(__name__) # noqa + + +class ReadTheDocsConfigJson(CDNCacheControlMixin, View): + def get(self, request): + + unresolved_domain = request.unresolved_domain + project = unresolved_domain.project + + # TODO: use Referrer header or GET arguments for Version / Build + version_slug = project.get_default_version() + version = project.versions.get(slug=version_slug) + build = version.builds.last() + + # TODO: define how it will be the exact JSON object returned here + data = { + "project": { + "slug": project.slug, + }, + "version": { + "slug": version.slug, + }, + "build": { + "id": build.pk, + }, + "domains": { + "dashboard": settings.PRODUCTION_DOMAIN, + }, + } + + return JsonResponse(data, json_dumps_params=dict(indent=4)) From 761e3b653be9f1ddca2893b161c63150993062d7 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Sat, 11 Mar 2023 20:54:10 +0100 Subject: [PATCH 19/40] Do not require `readthedocs-build.YAML` for now --- readthedocs/doc_builder/director.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readthedocs/doc_builder/director.py b/readthedocs/doc_builder/director.py index 5c43304be68..7c5becd9357 100644 --- a/readthedocs/doc_builder/director.py +++ b/readthedocs/doc_builder/director.py @@ -644,6 +644,10 @@ def generate_readthedocs_data_javascript(self): log.warning(yaml_path) data = yaml.safe_load(open(yaml_path, "r")) except Exception: + + # NOTE: skip this work for now until we decide whether or not this YAML file is required + return + # TODO: Improve this message raise BuildUserError( "The required 'readthedocs-build.yaml' file was not provided." From bd9f70e3d70878428f99923aa33588be5f185faa Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 13 Mar 2023 14:05:11 +0100 Subject: [PATCH 20/40] Expand the JSON response with more data --- readthedocs/proxito/views/hosting.py | 29 ++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/readthedocs/proxito/views/hosting.py b/readthedocs/proxito/views/hosting.py index 7882111796d..1df83650d4b 100644 --- a/readthedocs/proxito/views/hosting.py +++ b/readthedocs/proxito/views/hosting.py @@ -5,7 +5,9 @@ from django.http import JsonResponse from django.views import View +from readthedocs.builds.constants import EXTERNAL from readthedocs.core.mixins import CDNCacheControlMixin +from readthedocs.core.unresolver import unresolver log = structlog.get_logger(__name__) # noqa @@ -16,18 +18,25 @@ def get(self, request): unresolved_domain = request.unresolved_domain project = unresolved_domain.project + # TODO: why the UnresolvedURL object is not injected in the `request` by the middleware. + # Is is fine to calculate it here? + unresolved_url = unresolver.unresolve_url(request.headers.get("Referer")) + version = unresolved_url.version + # TODO: use Referrer header or GET arguments for Version / Build - version_slug = project.get_default_version() - version = project.versions.get(slug=version_slug) + project.get_default_version() build = version.builds.last() # TODO: define how it will be the exact JSON object returned here data = { "project": { "slug": project.slug, + "language": project.language, + "repository_url": project.repo, }, "version": { "slug": version.slug, + "external": version.type == EXTERNAL, }, "build": { "id": build.pk, @@ -35,6 +44,22 @@ def get(self, request): "domains": { "dashboard": settings.PRODUCTION_DOMAIN, }, + "features": { + "external_version_warning": { + "enabled": True, + "query_selector": "[role=main]", + }, + "non_latest_version_warning": { + "enabled": True, + "query_selector": "[role=main]", + "versions": list( + project.versions.filter(active=True).values_list( + "slug", flat=True + ) + ), + }, + "doc_diff": True, + }, } return JsonResponse(data, json_dumps_params=dict(indent=4)) From 842a22856dfae8b684227997afc7ae9bbb0c78a4 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 13 Mar 2023 14:06:51 +0100 Subject: [PATCH 21/40] Remove non-required files and rely on `readthedocs-client.js` only --- .../core/static/core/js/integrations.js | 44 ----------- .../static/core/js/readthedocs-doc-diff.js | 1 - .../static/core/js/readthedocs-hosting.js | 77 ------------------- .../doc_builder/readthedocs-data.html | 6 -- 4 files changed, 128 deletions(-) delete mode 100644 readthedocs/core/static/core/js/integrations.js delete mode 100644 readthedocs/core/static/core/js/readthedocs-doc-diff.js delete mode 100644 readthedocs/core/static/core/js/readthedocs-hosting.js delete mode 100644 readthedocs/doc_builder/templates/doc_builder/readthedocs-data.html diff --git a/readthedocs/core/static/core/js/integrations.js b/readthedocs/core/static/core/js/integrations.js deleted file mode 100644 index 4cecf362f3e..00000000000 --- a/readthedocs/core/static/core/js/integrations.js +++ /dev/null @@ -1,44 +0,0 @@ -// Unique entry point that our servers will inject - -// Load Read the Docs data first -// This data is generated at build time by the doctool -fetch("/en/manual-integration-docsify/readthedocs-data.html", {method: 'GET'}) - .then(response => { - return response.text(); - }) - .then(text => { - document.head.insertAdjacentHTML("beforeend", text); - }) - .then(() => { - // TODO: use `READTHEDOCS_DATA.features.hosting.version` to decide - // what version of these Javascript libraries we need to inject here. - // See https://github.com/readthedocs/readthedocs.org/issues/9063#issuecomment-1325483505 - let link = document.createElement("link"); - link.setAttribute("rel", "stylesheet"); - link.setAttribute("type", "text/css"); - link.setAttribute("href", "/_/static/css/readthedocs-doc-embed.css"); - document.head.appendChild(link); - - let embed = document.createElement("script"); - embed.setAttribute("async", "async"); - embed.setAttribute("src", "/_/static/javascript/readthedocs-doc-embed.js"); - document.head.appendChild(embed); - - let analytics = document.createElement("script"); - analytics.setAttribute("async", "async"); - analytics.setAttribute("src", "/_/static/javascript/readthedocs-analytics.js"); - document.head.appendChild(analytics); - - let hosting = document.createElement("script"); - hosting.setAttribute("async", "async"); - hosting.setAttribute("src", "/_/static/core/js/readthedocs-hosting.js"); - document.head.appendChild(hosting); - - // TODO: insert search-as-you-type once it becomes a JS library - // decoupled from Sphinx. - // See https://github.com/readthedocs/readthedocs-sphinx-search/issues/67 - - // TODO: find a way to remove the Sphinx default search, since it duplicates the results sometimes. - // This removal is currently happening at our Sphinx extension: - // https://github.com/readthedocs/readthedocs-sphinx-ext/blob/7cc1e60f7dcdeb7af35e3479509a621d5bac0976/readthedocs_ext/readthedocs.py#L239 - }); diff --git a/readthedocs/core/static/core/js/readthedocs-doc-diff.js b/readthedocs/core/static/core/js/readthedocs-doc-diff.js deleted file mode 100644 index 0fceba340d4..00000000000 --- a/readthedocs/core/static/core/js/readthedocs-doc-diff.js +++ /dev/null @@ -1 +0,0 @@ -(()=>{var e={416:(e,t,n)=>{"use strict";var r,i=n(224),o=n(52),a={addedClass:"doc-diff-added",modifiedClass:"doc-diff-modified",removedClass:"doc-diff-removed",skipModified:!0};function s(){var e={base_host:"",base_version:"latest",base_language:"en",base_page:"index.html",root_selector:"div.document[role='main']",inject_styles:!0};return new Promise((function(t,n){var r=document.querySelector("script#READTHEDOCS_DATA");if(r)try{var i=JSON.parse(r.innerText);e.base_host="https://"+i.project+".readthedocs.io",e.base_language=i.language,e.base_page=i.page+".html"}catch(e){console.debug("Error parsing configuration data",e)}var o=document.querySelector("script#doc-diff-config");if(o)try{var a=JSON.parse(o.innerText);Object.assign(e,a)}catch(e){console.debug("Error parsing configuration data",e)}return void 0===e.base_url&&(e.base_url=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"en",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"latest",r=arguments.length>3?arguments[3]:void 0,i=[];e&&(e="https://cors.writethedocs.workers.dev/corsproxy/?apiurl="+e);i=null==n&&null==t?[e,r]:null==t?[e,n,r]:[e,t,n,r];return i.join("/")}(e.base_host,e.base_language,e.base_version,e.base_page)),t(e)}))}e=n.hmd(e),n.c[n.s]!==e&&(r=new Promise((function(e){if("interactive"===document.readyState||"complete"===document.readyState)return e();document.addEventListener("DOMContentLoaded",(function(){e()}),{capture:!0,once:!0,passive:!0})})),new Promise((function(e){r.then((function(){return s()})).then((function(e){return function(e){return new Promise((function(t,n){fetch(e.base_url).then((function(e){return e.text()})).then((function(r){var s=(new DOMParser).parseFromString(r,"text/html").documentElement.querySelector(e.root_selector),f=document.querySelector(e.root_selector);null!=s&&null!=f||n(new Error("Element not found in both documents.")),e.inject_styles&&(document.adoptedStyleSheets=[o.Z]);var l=(0,i.visualDomDiff)(s,f,a);f.replaceWith(l.firstElementChild),t(!0)}))}))}(e)})).then((function(){e()})).catch((function(e){console.error(e.message)}))})))},52:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(81),i=n.n(r),o=n(645),a=n.n(o)()(i());a.push([e.id,".doc-diff-added {\n background-color: rgb(171, 242, 188);\n text-decoration: none;\n}\n\n.doc-diff-modified {\n}\n\n.doc-diff-removed {\n background-color: rgba(255, 129, 130, 0.4);\n text-decoration: none;\n}\n",""]);var s=new CSSStyleSheet;s.replaceSync(a.toString());const f=s},645:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n="",r=void 0!==t[5];return t[4]&&(n+="@supports (".concat(t[4],") {")),t[2]&&(n+="@media ".concat(t[2]," {")),r&&(n+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),n+=e(t),r&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,r,i,o){"string"==typeof e&&(e=[[null,e,void 0]]);var a={};if(r)for(var s=0;s0?" ".concat(h[5]):""," {").concat(h[1],"}")),h[5]=o),n&&(h[2]?(h[1]="@media ".concat(h[2]," {").concat(h[1],"}"),h[2]=n):h[2]=n),i&&(h[4]?(h[1]="@supports (".concat(h[4],") {").concat(h[1],"}"),h[4]=i):h[4]="".concat(i)),t.push(h))}},t}},81:e=>{"use strict";e.exports=function(e){return e[1]}},27:e=>{var t=function(){this.Diff_Timeout=1,this.Diff_EditCost=4,this.Match_Threshold=.5,this.Match_Distance=1e3,this.Patch_DeleteThreshold=.5,this.Patch_Margin=4,this.Match_MaxBits=32},n=-1;t.Diff=function(e,t){return[e,t]},t.prototype.diff_main=function(e,n,r,i){void 0===i&&(i=this.Diff_Timeout<=0?Number.MAX_VALUE:(new Date).getTime()+1e3*this.Diff_Timeout);var o=i;if(null==e||null==n)throw new Error("Null input. (diff_main)");if(e==n)return e?[new t.Diff(0,e)]:[];void 0===r&&(r=!0);var a=r,s=this.diff_commonPrefix(e,n),f=e.substring(0,s);e=e.substring(s),n=n.substring(s),s=this.diff_commonSuffix(e,n);var l=e.substring(e.length-s);e=e.substring(0,e.length-s),n=n.substring(0,n.length-s);var h=this.diff_compute_(e,n,a,o);return f&&h.unshift(new t.Diff(0,f)),l&&h.push(new t.Diff(0,l)),this.diff_cleanupMerge(h),h},t.prototype.diff_compute_=function(e,r,i,o){var a;if(!e)return[new t.Diff(1,r)];if(!r)return[new t.Diff(n,e)];var s=e.length>r.length?e:r,f=e.length>r.length?r:e,l=s.indexOf(f);if(-1!=l)return a=[new t.Diff(1,s.substring(0,l)),new t.Diff(0,f),new t.Diff(1,s.substring(l+f.length))],e.length>r.length&&(a[0][0]=a[2][0]=n),a;if(1==f.length)return[new t.Diff(n,e),new t.Diff(1,r)];var h=this.diff_halfMatch_(e,r);if(h){var u=h[0],c=h[1],d=h[2],g=h[3],p=h[4],v=this.diff_main(u,d,i,o),_=this.diff_main(c,g,i,o);return v.concat([new t.Diff(0,p)],_)}return i&&e.length>100&&r.length>100?this.diff_lineMode_(e,r,o):this.diff_bisect_(e,r,o)},t.prototype.diff_lineMode_=function(e,r,i){var o=this.diff_linesToChars_(e,r);e=o.chars1,r=o.chars2;var a=o.lineArray,s=this.diff_main(e,r,!1,i);this.diff_charsToLines_(s,a),this.diff_cleanupSemantic(s),s.push(new t.Diff(0,""));for(var f=0,l=0,h=0,u="",c="";f=1&&h>=1){s.splice(f-l-h,l+h),f=f-l-h;for(var d=this.diff_main(u,c,!1,i),g=d.length-1;g>=0;g--)s.splice(f,0,d[g]);f+=d.length}h=0,l=0,u="",c=""}f++}return s.pop(),s},t.prototype.diff_bisect_=function(e,r,i){for(var o=e.length,a=r.length,s=Math.ceil((o+a)/2),f=s,l=2*s,h=new Array(l),u=new Array(l),c=0;ci);m++){for(var y=-m+p;y<=m-v;y+=2){for(var w=f+y,x=(T=y==-m||y!=m&&h[w-1]o)v+=2;else if(x>a)p+=2;else if(g){if((M=f+d-y)>=0&&M=(N=o-u[M]))return this.diff_bisectSplit_(e,r,T,x,i)}}for(var D=-m+_;D<=m-b;D+=2){for(var N,M=f+D,E=(N=D==-m||D!=m&&u[M-1]o)b+=2;else if(E>a)_+=2;else if(!g){if((w=f+d-D)>=0&&w=(N=o-N))return this.diff_bisectSplit_(e,r,T,x,i)}}}}return[new t.Diff(n,e),new t.Diff(1,r)]},t.prototype.diff_bisectSplit_=function(e,t,n,r,i){var o=e.substring(0,n),a=t.substring(0,r),s=e.substring(n),f=t.substring(r),l=this.diff_main(o,a,!1,i),h=this.diff_main(s,f,!1,i);return l.concat(h)},t.prototype.diff_linesToChars_=function(e,t){var n=[],r={};function i(e){for(var t="",i=0,a=-1,s=n.length;ar?e=e.substring(n-r):nt.length?e:t,r=e.length>t.length?t:e;if(n.length<4||2*r.length=e.length?[r,o,a,s,h]:null}var a,s,f,l,h,u=o(n,r,Math.ceil(n.length/4)),c=o(n,r,Math.ceil(n.length/2));return u||c?(a=c?u&&u[4].length>c[4].length?u:c:u,e.length>t.length?(s=a[0],f=a[1],l=a[2],h=a[3]):(l=a[0],h=a[1],s=a[2],f=a[3]),[s,f,l,h,a[4]]):null},t.prototype.diff_cleanupSemantic=function(e){for(var r=!1,i=[],o=0,a=null,s=0,f=0,l=0,h=0,u=0;s0?i[o-1]:-1,f=0,l=0,h=0,u=0,a=null,r=!0)),s++;for(r&&this.diff_cleanupMerge(e),this.diff_cleanupSemanticLossless(e),s=1;s=p?(g>=c.length/2||g>=d.length/2)&&(e.splice(s,0,new t.Diff(0,d.substring(0,g))),e[s-1][1]=c.substring(0,c.length-g),e[s+1][1]=d.substring(g),s++):(p>=c.length/2||p>=d.length/2)&&(e.splice(s,0,new t.Diff(0,c.substring(0,p))),e[s-1][0]=1,e[s-1][1]=d.substring(0,d.length-p),e[s+1][0]=n,e[s+1][1]=c.substring(p),s++),s++}s++}},t.prototype.diff_cleanupSemanticLossless=function(e){function n(e,n){if(!e||!n)return 6;var r=e.charAt(e.length-1),i=n.charAt(0),o=r.match(t.nonAlphaNumericRegex_),a=i.match(t.nonAlphaNumericRegex_),s=o&&r.match(t.whitespaceRegex_),f=a&&i.match(t.whitespaceRegex_),l=s&&r.match(t.linebreakRegex_),h=f&&i.match(t.linebreakRegex_),u=l&&e.match(t.blanklineEndRegex_),c=h&&n.match(t.blanklineStartRegex_);return u||c?5:l||h?4:o&&!s&&f?3:s||f?2:o||a?1:0}for(var r=1;r=c&&(c=d,l=i,h=o,u=a)}e[r-1][1]!=l&&(l?e[r-1][1]=l:(e.splice(r-1,1),r--),e[r][1]=h,u?e[r+1][1]=u:(e.splice(r+1,1),r--))}r++}},t.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/,t.whitespaceRegex_=/\s/,t.linebreakRegex_=/[\r\n]/,t.blanklineEndRegex_=/\n\r?\n$/,t.blanklineStartRegex_=/^\r?\n\r?\n/,t.prototype.diff_cleanupEfficiency=function(e){for(var r=!1,i=[],o=0,a=null,s=0,f=!1,l=!1,h=!1,u=!1;s0?i[o-1]:-1,h=u=!1),r=!0)),s++;r&&this.diff_cleanupMerge(e)},t.prototype.diff_cleanupMerge=function(e){e.push(new t.Diff(0,""));for(var r,i=0,o=0,a=0,s="",f="";i1?(0!==o&&0!==a&&(0!==(r=this.diff_commonPrefix(f,s))&&(i-o-a>0&&0==e[i-o-a-1][0]?e[i-o-a-1][1]+=f.substring(0,r):(e.splice(0,0,new t.Diff(0,f.substring(0,r))),i++),f=f.substring(r),s=s.substring(r)),0!==(r=this.diff_commonSuffix(f,s))&&(e[i][1]=f.substring(f.length-r)+e[i][1],f=f.substring(0,f.length-r),s=s.substring(0,s.length-r))),i-=o+a,e.splice(i,o+a),s.length&&(e.splice(i,0,new t.Diff(n,s)),i++),f.length&&(e.splice(i,0,new t.Diff(1,f)),i++),i++):0!==i&&0==e[i-1][0]?(e[i-1][1]+=e[i][1],e.splice(i,1)):i++,a=0,o=0,s="",f=""}""===e[e.length-1][1]&&e.pop();var l=!1;for(i=1;it));r++)a=i,s=o;return e.length!=r&&e[r][0]===n?s:s+(t-a)},t.prototype.diff_prettyHtml=function(e){for(var t=[],r=/&/g,i=//g,a=/\n/g,s=0;s");switch(f){case 1:t[s]=''+l+"";break;case n:t[s]=''+l+"";break;case 0:t[s]=""+l+""}}return t.join("")},t.prototype.diff_text1=function(e){for(var t=[],n=0;nthis.Match_MaxBits)throw new Error("Pattern too long for this browser.");var r=this.match_alphabet_(t),i=this;function o(e,r){var o=e/t.length,a=Math.abs(n-r);return i.Match_Distance?o+a/i.Match_Distance:a?1:o}var a=this.Match_Threshold,s=e.indexOf(t,n);-1!=s&&(a=Math.min(o(0,s),a),-1!=(s=e.lastIndexOf(t,n+t.length))&&(a=Math.min(o(0,s),a)));var f,l,h=1<=g;_--){var b=r[e.charAt(_-1)];if(v[_]=0===d?(v[_+1]<<1|1)&b:(v[_+1]<<1|1)&b|(u[_+1]|u[_])<<1|1|u[_+1],v[_]&h){var m=o(d,_-1);if(m<=a){if(a=m,!((s=_-1)>n))break;g=Math.max(1,2*n-s)}}}if(o(d+1,n)>a)break;u=v}return s},t.prototype.match_alphabet_=function(e){for(var t={},n=0;n2&&(this.diff_cleanupSemantic(a),this.diff_cleanupEfficiency(a));else if(e&&"object"==typeof e&&void 0===r&&void 0===i)a=e,o=this.diff_text1(a);else if("string"==typeof e&&r&&"object"==typeof r&&void 0===i)o=e,a=r;else{if("string"!=typeof e||"string"!=typeof r||!i||"object"!=typeof i)throw new Error("Unknown call format to patch_make.");o=e,a=i}if(0===a.length)return[];for(var s=[],f=new t.patch_obj,l=0,h=0,u=0,c=o,d=o,g=0;g=2*this.Patch_Margin&&l&&(this.patch_addContext_(f,c),s.push(f),f=new t.patch_obj,l=0,c=d,h=u)}1!==p&&(h+=v.length),p!==n&&(u+=v.length)}return l&&(this.patch_addContext_(f,c),s.push(f)),s},t.prototype.patch_deepCopy=function(e){for(var n=[],r=0;rthis.Match_MaxBits?-1!=(s=this.match_main(t,h.substring(0,this.Match_MaxBits),l))&&(-1==(u=this.match_main(t,h.substring(h.length-this.Match_MaxBits),l+h.length-this.Match_MaxBits))||s>=u)&&(s=-1):s=this.match_main(t,h,l),-1==s)o[a]=!1,i-=e[a].length2-e[a].length1;else if(o[a]=!0,i=s-l,h==(f=-1==u?t.substring(s,s+h.length):t.substring(s,u+this.Match_MaxBits)))t=t.substring(0,s)+this.diff_text2(e[a].diffs)+t.substring(s+h.length);else{var c=this.diff_main(h,f,!1);if(h.length>this.Match_MaxBits&&this.diff_levenshtein(c)/h.length>this.Patch_DeleteThreshold)o[a]=!1;else{this.diff_cleanupSemanticLossless(c);for(var d,g=0,p=0;pa[0][1].length){var s=n-a[0][1].length;a[0][1]=r.substring(a[0][1].length)+a[0][1],o.start1-=s,o.start2-=s,o.length1+=s,o.length2+=s}if(0==(a=(o=e[e.length-1]).diffs).length||0!=a[a.length-1][0])a.push(new t.Diff(0,r)),o.length1+=n,o.length2+=n;else if(n>a[a.length-1][1].length){s=n-a[a.length-1][1].length;a[a.length-1][1]+=r.substring(0,s),o.length1+=s,o.length2+=s}return r},t.prototype.patch_splitMax=function(e){for(var r=this.Match_MaxBits,i=0;i2*r?(l.length1+=c.length,a+=c.length,h=!1,l.diffs.push(new t.Diff(u,c)),o.diffs.shift()):(c=c.substring(0,r-l.length1-this.Patch_Margin),l.length1+=c.length,a+=c.length,0===u?(l.length2+=c.length,s+=c.length):h=!1,l.diffs.push(new t.Diff(u,c)),c==o.diffs[0][1]?o.diffs.shift():o.diffs[0][1]=o.diffs[0][1].substring(c.length))}f=(f=this.diff_text2(l.diffs)).substring(f.length-this.Patch_Margin);var d=this.diff_text1(o.diffs).substring(0,this.Patch_Margin);""!==d&&(l.length1+=d.length,l.length2+=d.length,0!==l.diffs.length&&0===l.diffs[l.diffs.length-1][0]?l.diffs[l.diffs.length-1][1]+=d:l.diffs.push(new t.Diff(0,d))),h||e.splice(++i,0,l)}}},t.prototype.patch_toText=function(e){for(var t=[],n=0;n{"use strict";n.r(t),n.d(t,{__assign:()=>o,__asyncDelegator:()=>w,__asyncGenerator:()=>y,__asyncValues:()=>x,__await:()=>m,__awaiter:()=>h,__classPrivateFieldGet:()=>T,__classPrivateFieldIn:()=>O,__classPrivateFieldSet:()=>S,__createBinding:()=>c,__decorate:()=>s,__exportStar:()=>d,__extends:()=>i,__generator:()=>u,__importDefault:()=>E,__importStar:()=>M,__makeTemplateObject:()=>D,__metadata:()=>l,__param:()=>f,__read:()=>p,__rest:()=>a,__spread:()=>v,__spreadArray:()=>b,__spreadArrays:()=>_,__values:()=>g});var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},r(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var o=function(){return o=Object.assign||function(e){for(var t,n=1,r=arguments.length;n=0;s--)(i=e[s])&&(a=(o<3?i(a):o>3?i(t,n,a):i(t,n))||a);return o>3&&a&&Object.defineProperty(t,n,a),a}function f(e,t){return function(n,r){t(n,r,e)}}function l(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}function h(e,t,n,r){return new(n||(n=Promise))((function(i,o){function a(e){try{f(r.next(e))}catch(e){o(e)}}function s(e){try{f(r.throw(e))}catch(e){o(e)}}function f(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}f((r=r.apply(e,t||[])).next())}))}function u(e,t){var n,r,i,o,a={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function s(o){return function(s){return function(o){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(i=2&o[0]?r.return:o[0]?r.throw||((i=r.return)&&i.call(r),0):r.next)&&!(i=i.call(r,o[1])).done)return i;switch(r=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return a.label++,{value:o[1],done:!1};case 5:a.label++,r=o[1],o=[0];continue;case 7:o=a.ops.pop(),a.trys.pop();continue;default:if(!(i=a.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function p(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,i,o=n.call(e),a=[];try{for(;(void 0===t||t-- >0)&&!(r=o.next()).done;)a.push(r.value)}catch(e){i={error:e}}finally{try{r&&!r.done&&(n=o.return)&&n.call(o)}finally{if(i)throw i.error}}return a}function v(){for(var e=[],t=0;t1||s(e,t)}))})}function s(e,t){try{(n=i[e](t)).value instanceof m?Promise.resolve(n.value.v).then(f,l):h(o[0][2],n)}catch(e){h(o[0][3],e)}var n}function f(e){s("next",e)}function l(e){s("throw",e)}function h(e,t){e(t),o.shift(),o.length&&s(o[0][0],o[0][1])}}function w(e){var t,n;return t={},r("next"),r("throw",(function(e){throw e})),r("return"),t[Symbol.iterator]=function(){return this},t;function r(r,i){t[r]=e[r]?function(t){return(n=!n)?{value:m(e[r](t)),done:"return"===r}:i?i(t):t}:i}}function x(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e=g(e),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(n){t[n]=e[n]&&function(t){return new Promise((function(r,i){(function(e,t,n,r){Promise.resolve(r).then((function(t){e({value:t,done:n})}),t)})(r,i,(t=e[n](t)).done,t.value)}))}}}function D(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e}var N=Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t};function M(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&c(t,e,n);return N(t,e),t}function E(e){return e&&e.__esModule?e:{default:e}}function T(e,t,n,r){if("a"===n&&!r)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?r:"a"===n?r.call(e):r?r.value:t.get(e)}function S(e,t,n,r,i){if("m"===r)throw new TypeError("Private method is not writable");if("a"===r&&!i)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!i:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===r?i.call(e,n):i?i.value=n:t.set(e,n),n}function O(e,t){if(null===t||"object"!=typeof t&&"function"!=typeof t)throw new TypeError("Cannot use 'in' operator on non-object");return"function"==typeof e?t===e:e.has(t)}},967:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(402),i=new Set;i.add("IMG"),i.add("VIDEO"),i.add("IFRAME"),i.add("OBJECT"),i.add("SVG");var o=new Set;o.add("BDO"),o.add("BDI"),o.add("Q"),o.add("CITE"),o.add("CODE"),o.add("DATA"),o.add("TIME"),o.add("VAR"),o.add("DFN"),o.add("ABBR"),o.add("STRONG"),o.add("EM"),o.add("BIG"),o.add("SMALL"),o.add("MARK"),o.add("SUB"),o.add("SUP"),o.add("SAMP"),o.add("KBD"),o.add("B"),o.add("I"),o.add("S"),o.add("U"),o.add("SPAN"),t.optionsToConfig=function(e){var t=void 0===e?{}:e,n=t.addedClass,a=void 0===n?"vdd-added":n,s=t.modifiedClass,f=void 0===s?"vdd-modified":s,l=t.removedClass,h=void 0===l?"vdd-removed":l,u=t.skipModified,c=void 0!==u&&u,d=t.skipChildren,g=t.skipSelf,p=t.diffText;return{addedClass:a,diffText:void 0===p?r.diffText:p,modifiedClass:f,removedClass:h,skipModified:c,skipChildren:function(e){if(!r.isElement(e)&&!r.isDocumentFragment(e)&&!r.isDocument(e))return!0;if(d){var t=d(e);if("boolean"==typeof t)return t}return i.has(e.nodeName)},skipSelf:function(e){if(!r.isText(e)&&!r.isElement(e))return!0;if(g){var t=g(e);if("boolean"==typeof t)return t}return o.has(e.nodeName)}}}},145:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(27),i=n(967),o=n(844),a=n(402),s=function(e){return"TH"===e?"TD":e},f=function(e,t){return new o.DomIterator(e,t).reduce((function(e,t){return e+(a.isText(t)?t.data:a.charForNodeName(s(t.nodeName)))}),"")},l=function(e){return a.isText(e)?e.length:1},h=function(e){return"TR"===e.nodeName},u={skipChildren:h,skipSelf:function(e){return!h(e)}};t.visualDomDiff=function e(t,n,h){var c,d;void 0===h&&(h={});var g,p,v,_,b,m=n.ownerDocument||n,y=i.optionsToConfig(h),w=y.addedClass,x=y.diffText,D=y.modifiedClass,N=y.removedClass,M=y.skipSelf,E=y.skipChildren,T=function(e){return!M(e)},S=function(e,t){return a.getAncestors(e,t).filter(T).length},O=function(e){return a.isElement(e)&&M(e)},A=function(e,t){return a.getAncestors(e,t).filter(O).reverse()},C=function(e){return Z.has(e)?1:J.has(e)?-1:0},P=x(f(t,y),f(n,y)),k=0,I=new o.DomIterator(t,y),j=new o.DomIterator(n,y),F=0,R=0,B=0;v=P[k++],c=I.next(),g=c.done,_=c.value,d=j.next(),p=d.done,b=d.value;var L=m.createDocumentFragment(),U=L,q=0,Q=L,V=0,G=null,H=null,J=new Set,Z=new Set,$=new Set,z=new Map,K=new Array,X=new Map;function Y(){for(var e=S(_,t);q>e;){if(!U.parentNode)return a.never();U===G&&(G=null),U=U.parentNode,q--}if(q!==e)return a.never()}function W(){for(var e=S(b,n);V>e;){if(!Q.parentNode)return a.never();Q===H&&(H=null),Q=Q.parentNode,V--}if(V!==e)return a.never()}function ee(e){if(U!==Q||H||G)return a.never();if(a.isText(e)){var r=A(_,t),i=A(b,n);z.set(e,i);var o=r.length;if(o!==i.length)$.add(e);else for(var s=0;st)return a.never()}function ie(e){var t,n=l(_);if((R+=e)===n)t=I.next(),g=t.done,_=t.value,R=0;else if(R>n)return a.never()}function oe(e){var t,n=l(b);if((B+=e)===n)t=j.next(),p=t.done,b=t.value,B=0;else if(B>n)return a.never()}for(;v;)if(v[0]===r.DIFF_DELETE){if(g)return a.never();Y();var ae=Math.min(v[1].length-F,l(_)-R),se=v[1].substring(F,F+ae);te(a.isText(_)?m.createTextNode(se):_.cloneNode(!1)),re(ae),ie(ae)}else if(v[0]===r.DIFF_INSERT){if(p)return a.never();W();var fe=Math.min(v[1].length-F,l(b)-B);se=v[1].substring(F,F+fe);ne(a.isText(b)?m.createTextNode(se):b.cloneNode(!1)),re(fe),oe(fe)}else{if(g||p)return a.never();Y(),W();var le=Math.min(v[1].length-F,l(_)-R,l(b)-B);se=v[1].substring(F,F+le);U===Q&&(a.isText(_)&&a.isText(b)||s(_.nodeName)===s(b.nodeName)&&!E(_)&&!E(b)||a.areNodesEqual(_,b))?ee(a.isText(b)?m.createTextNode(se):b.cloneNode(!1)):(te(a.isText(_)?m.createTextNode(se):_.cloneNode(!1)),ne(a.isText(b)?m.createTextNode(se):b.cloneNode(!1))),re(le),ie(le),oe(le)}return J.forEach((function(e){for(var t=e.parentNode,n=e.previousSibling;n&&Z.has(n);)t.insertBefore(e,n),n=e.previousSibling})),K.forEach((function(t){var n=t.newTable,r=t.oldTable,i=t.outputTable;if(!a.isTableValid(r,!0)||!a.isTableValid(n,!0)||!a.isTableValid(i,!1)){new o.DomIterator(i).forEach((function(e){Z.delete(e),J.delete(e),$.delete(e),z.delete(e)}));var s=i.parentNode,f=r.cloneNode(!0),l=n.cloneNode(!0);return s.insertBefore(f,i),s.insertBefore(l,i),s.removeChild(i),J.add(f),void Z.add(l)}var c=[];new o.DomIterator(i,u).some((function(e){var t=X.get(e);if(!t)return!1;var n=t.oldRow,r=t.newRow,i=n.childNodes.length,o=r.childNodes.length,a=Math.max(i,o),s=Math.min(i,o);if(e.childNodes.length===a)for(var f=e.childNodes,l=0,h=f.length;l{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e,t){this.rootNode=e,this.config=t,this.descend=!0,this.nextNode=this.rootNode,this.skipSelf(this.nextNode)&&this.next()}return e.prototype.toArray=function(){for(var e,t=[],n=this.next(),r=n.done,i=n.value;!r;)t.push(i),r=(e=this.next()).done,i=e.value;return t},e.prototype.forEach=function(e){for(var t,n=this.next(),r=n.done,i=n.value;!r;)e(i),r=(t=this.next()).done,i=t.value},e.prototype.reduce=function(e,t){for(var n,r=t,i=this.next(),o=i.done,a=i.value;!o;)r=e(r,a),o=(n=this.next()).done,a=n.value;return r},e.prototype.some=function(e){for(var t,n=this.next(),r=n.done,i=n.value;!r;){if(e(i))return!0;r=(t=this.next()).done,i=t.value}return!1},e.prototype.next=function(){if(!this.nextNode)return{done:!0,value:this.rootNode};var e=this.nextNode;return this.descend&&this.nextNode.firstChild&&!this.skipChildren(this.nextNode)?this.nextNode=this.nextNode.firstChild:this.nextNode===this.rootNode?this.nextNode=null:this.nextNode.nextSibling?(this.nextNode=this.nextNode.nextSibling,this.descend=!0):(this.nextNode=this.nextNode.parentNode,this.descend=!1,this.next()),this.nextNode&&this.skipSelf(this.nextNode)&&this.next(),{done:!1,value:e}},e.prototype.skipSelf=function(e){return!(!this.config||!this.config.skipSelf)&&this.config.skipSelf(e)},e.prototype.skipChildren=function(e){return!(!this.config||!this.config.skipChildren)&&this.config.skipChildren(e)},e}();t.DomIterator=n},224:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(655).__exportStar(n(145),t)},402:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(27);function i(e){return e.nodeType===e.ELEMENT_NODE}function o(e){return e.nodeType===e.TEXT_NODE}function a(e){return e.nodeType===e.COMMENT_NODE}function s(e,t){return e===t}function f(e,t,n){if(void 0===n&&(n=s),e.length!==t.length)return!1;for(var r=0,i=e.length;r="豈"?t++:(n[1]=a.substring(0,a.length-1),i[1]=l+s.substring(0,s.length-1),o[1]=l+f,0===n[1].length&&e.splice(t,1))}else t++}}t.isElement=i,t.isText=o,t.isDocument=function(e){return e.nodeType===e.DOCUMENT_NODE},t.isDocumentFragment=function(e){return e.nodeType===e.DOCUMENT_FRAGMENT_NODE},t.isComment=a,t.strictEqual=s,t.areArraysEqual=f,t.areNodesEqual=function e(t,n,r){if(void 0===r&&(r=!1),t===n)return!0;if(t.nodeType!==n.nodeType||t.nodeName!==n.nodeName)return!1;if(o(t)||a(t)){if(t.data!==n.data)return!1}else if(i(t)){var s=l(t).sort();if(!f(s,l(n).sort()))return!1;for(var h=0,u=s.length;h0&&o.push([r.DIFF_EQUAL,l.substring(0,g)]),c.diff_cleanupSemantic(o),d(i,o),o.length=0,i.push([r.DIFF_EQUAL,l.substring(g,h-p)]),p>0&&o.push([r.DIFF_EQUAL,l.substring(h-p)])}else o.push(f)}else o.push(f)}return c.diff_cleanupSemantic(o),d(i,o),o.length=0,c.diff_cleanupMerge(i),u(i),i},t.markUpNode=function(e,t,n){var r=e.ownerDocument,o=e.parentNode,a=e.previousSibling;if(i(e))e.classList.add(n);else if(a&&a.nodeName===t&&a.classList.contains(n))a.appendChild(e);else{var s=r.createElement(t);s.classList.add(n),o.insertBefore(s,e),s.appendChild(e)}},t.isTableValid=function(e,t){var n;return function(e){var t=e.childNodes,n=t.length,i=0;i{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:()=>{throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};n(n.s=416)})(); \ No newline at end of file diff --git a/readthedocs/core/static/core/js/readthedocs-hosting.js b/readthedocs/core/static/core/js/readthedocs-hosting.js deleted file mode 100644 index 1798d990bd1..00000000000 --- a/readthedocs/core/static/core/js/readthedocs-hosting.js +++ /dev/null @@ -1,77 +0,0 @@ -READTHEDOCS_DATA = JSON.parse(document.getElementById('READTHEDOCS_DATA').textContent); - -function injectExternalVersionWarning() { - // TODO: make all these banners (injected HTML) templates that users can override with their own. - // This way, we allow customization of the look&feel without compromising the logic. - let admonition = ` -
-

Warning

-

- This page - was created - from a pull request - (#${ READTHEDOCS_DATA.version }). -

-
-`; - - let main = document.querySelector('[role=main]') || document.querySelector('#main'); - let node = document.createElement("div"); - node.innerHTML = admonition; - main.insertBefore(node, main.firstChild); -} - -function injectDocDiff() { - let docdiff = document.createElement("script"); - docdiff.setAttribute("async", "async"); - docdiff.setAttribute("src", "/_/static/core/js/readthedocs-doc-diff.js"); - document.head.appendChild(docdiff); -} - -function injectOldVersionWarning() { - // TODO: compute if the user is reading the latest version or not before showing the warning. - let admonition = ` -
-

Warning

-

- This page documents version - ${ READTHEDOCS_DATA.version }. - The latest version is - ${ READTHEDOCS_DATA.version }. -

-
-`; - - // Borrowed and adapted from: - // https://github.com/readthedocs/readthedocs.org/blob/7ce98a4d4f34a4c1845dc6e3e0e5112af7c39b0c/readthedocs/core/static-src/core/js/doc-embed/version-compare.js#L1 - let main = document.querySelector('[role=main]') || document.querySelector('#main'); - let node = document.createElement("div"); - node.innerHTML = admonition; - main.insertBefore(node, main.firstChild); -} - - -window.addEventListener("load", (event) => { - // TODO: use the proxied API here - // "repository_url" could be retrived using the API, but there are some CORS issues and design decisions - // that it's probably smart to avoid and just rely on a fixed value from the build output :) - if (READTHEDOCS_DATA.build.external_version === true) { - injectExternalVersionWarning(); - - if (READTHEDOCS_DATA.features.docdiff.enabled === true) { - if(!window.location.pathname.endsWith("search.html")) { - // Avoid injecting doc-diff on search page because it doesn't make sense - injectDocDiff(); - } - } - } - else { - // TODO: there some data we need from `/api/v2/footer_html/`, - // like `is_highest` and `show_version_warning`. - // However, this call is happening inside the `readthedocs-doc-embed.js`. - // We could make the call again here for now as demo, - // but it would be good to refactor that code - // Inject old version warning only for non-external versions - injectOldVersionWarning(); - } -}); diff --git a/readthedocs/doc_builder/templates/doc_builder/readthedocs-data.html b/readthedocs/doc_builder/templates/doc_builder/readthedocs-data.html deleted file mode 100644 index 91ea9a3d1eb..00000000000 --- a/readthedocs/doc_builder/templates/doc_builder/readthedocs-data.html +++ /dev/null @@ -1,6 +0,0 @@ -{{ data|json_script:"READTHEDOCS_DATA" }} - -{% comment %} -The resulting file, will be available to use as: -const value = JSON.parse(document.getElementById('readthedocs-data').textContent); -{% endcomment %} From 2ad30ccbbab9828305ea7daadeeba21210269a00 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 13 Mar 2023 14:08:58 +0100 Subject: [PATCH 22/40] Improve helper text --- readthedocs/projects/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/projects/models.py b/readthedocs/projects/models.py index 6613a649145..e42a381c3cf 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -2061,7 +2061,7 @@ def add_features(sender, **kwargs): ), ( HOSTING_INTEGRATIONS, - _("Inject 'integrations.js' as \n'; - # sub_filter_types text/html; + # TODO: find a way to make this work _without_ running `npm run dev` from the `readthedocs-client` repository + sub_filter '' '\n'; sub_filter_last_modified on; sub_filter_once on; } From 2d7b6fe9fe0110c25e9cb7b94d3010753c76482f Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 20 Mar 2023 10:57:16 +0100 Subject: [PATCH 35/40] Update URL to remove .json from it --- readthedocs/proxito/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/proxito/urls.py b/readthedocs/proxito/urls.py index a1d70c4ef80..1973c342431 100644 --- a/readthedocs/proxito/urls.py +++ b/readthedocs/proxito/urls.py @@ -117,7 +117,7 @@ ), # readthedocs-config.js path( - f"{DOC_PATH_PREFIX}readthedocs-config.json", + f"{DOC_PATH_PREFIX}readthedocs-config/", ReadTheDocsConfigJson.as_view(), name="proxito_readthedocs_config_json", ), From ab43635a1a8fb7a9a273b30377198ef9dc01690e Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 20 Mar 2023 11:27:20 +0100 Subject: [PATCH 36/40] Remove non-required f-string --- readthedocs/proxito/views/hosting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readthedocs/proxito/views/hosting.py b/readthedocs/proxito/views/hosting.py index 6564e41790c..3552ac52375 100644 --- a/readthedocs/proxito/views/hosting.py +++ b/readthedocs/proxito/views/hosting.py @@ -85,12 +85,12 @@ def get(self, request): "doc_diff": { "enabled": True, # "http://test-builds-local.devthedocs.org/en/latest/index.html" - "base_url": f"""{resolver.resolve( + "base_url": resolver.resolve( project=project, version_slug=project.get_default_version(), language=project.language, filename=unresolved_url.filename, - )}""", + ), "root_selector": "[role=main]", "inject_styles": True, # NOTE: `base_host` and `base_page` are not required, since From 85ab2e7a443de6f8b3ececa7f06a9031028e333f Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 20 Mar 2023 11:27:37 +0100 Subject: [PATCH 37/40] Allow saving `build_data` via API endpoint --- readthedocs/api/v2/serializers.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/readthedocs/api/v2/serializers.py b/readthedocs/api/v2/serializers.py index 4a5c03e758a..aad6ac57c43 100644 --- a/readthedocs/api/v2/serializers.py +++ b/readthedocs/api/v2/serializers.py @@ -101,7 +101,7 @@ class VersionSerializer(serializers.ModelSerializer): class Meta: model = Version - fields = ( + fields = [ 'id', 'project', 'slug', @@ -116,7 +116,7 @@ class Meta: 'has_epub', 'has_htmlzip', 'documentation_type', - ) + ] class VersionAdminSerializer(VersionSerializer): @@ -124,6 +124,12 @@ class VersionAdminSerializer(VersionSerializer): """Version serializer that returns admin project data.""" project = ProjectAdminSerializer() + build_data = serializers.JSONField(required=False, write_only=True) + + class Meta(VersionSerializer.Meta): + fields = VersionSerializer.Meta.fields + [ + "build_data", + ] class BuildCommandSerializer(serializers.ModelSerializer): From 6154c7fc6211e62d32362e03fb163e98c3c4e181 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 20 Mar 2023 11:37:33 +0100 Subject: [PATCH 38/40] Lint --- readthedocs/builds/models.py | 2 -- readthedocs/projects/tasks/builds.py | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/readthedocs/builds/models.py b/readthedocs/builds/models.py index 8c7aff5d0ad..dc83b11c34b 100644 --- a/readthedocs/builds/models.py +++ b/readthedocs/builds/models.py @@ -65,11 +65,9 @@ BITBUCKET_COMMIT_URL, BITBUCKET_URL, DOCTYPE_CHOICES, - GITHUB_BRAND, GITHUB_COMMIT_URL, GITHUB_PULL_REQUEST_COMMIT_URL, GITHUB_URL, - GITLAB_BRAND, GITLAB_COMMIT_URL, GITLAB_MERGE_REQUEST_COMMIT_URL, GITLAB_URL, diff --git a/readthedocs/projects/tasks/builds.py b/readthedocs/projects/tasks/builds.py index af9c0f2d9fb..d1b4f31a6d1 100644 --- a/readthedocs/projects/tasks/builds.py +++ b/readthedocs/projects/tasks/builds.py @@ -103,7 +103,10 @@ class TaskData: build_commit: str = None start_time: timezone.datetime = None + + # pylint: disable=unsubscriptable-object environment_class: type[DockerBuildEnvironment] | type[LocalBuildEnvironment] = None + build_director: BuildDirector = None config: BuildConfigV1 | BuildConfigV2 = None project: APIProject = None @@ -572,7 +575,7 @@ def get_valid_artifact_types(self): artifact_type=artifact_type ) ) - elif artifact_format_files == 0: + if artifact_format_files == 0: raise BuildUserError( BuildUserError.BUILD_OUTPUT_HAS_0_FILES.format( artifact_type=artifact_type From 0e8f245cd1503bf5dbf0388c0ba76451d825f1c3 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 20 Mar 2023 12:12:10 +0100 Subject: [PATCH 39/40] Migrate nodejs installation to asdf --- scripts/circle/install_node.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/circle/install_node.sh b/scripts/circle/install_node.sh index bfde0987a35..da9cdb4f106 100755 --- a/scripts/circle/install_node.sh +++ b/scripts/circle/install_node.sh @@ -2,10 +2,11 @@ set -ev if [ $NODE_VERSION ] then - curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash - source ~/.nvm/nvm.sh - nvm install $NODE_VERSION - nvm use $NODE_VERSION + git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.11.3 + . "$HOME/.asdf/asdf.sh" + asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git + asdf install nodejs $NODE_VERSION + asdf global nodejs $NODE_VERSION npm install -g bower npm install bower install From a6c5977dd8aa1dd9fcf056edd030c37da95563b2 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 20 Mar 2023 13:14:28 +0100 Subject: [PATCH 40/40] Change port to match `npm run dev` from readthedocs-client --- dockerfiles/nginx/proxito.conf.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dockerfiles/nginx/proxito.conf.template b/dockerfiles/nginx/proxito.conf.template index 64e68c1cb05..dfe4fbd18c5 100644 --- a/dockerfiles/nginx/proxito.conf.template +++ b/dockerfiles/nginx/proxito.conf.template @@ -96,7 +96,7 @@ server { # Inject our own script dynamically # TODO: find a way to make this work _without_ running `npm run dev` from the `readthedocs-client` repository - sub_filter '' '\n'; + sub_filter '' '\n'; sub_filter_last_modified on; sub_filter_once on; }