#35371: JS module export regex does not handle certain minified code correctly
-----------------------------------------------+------------------------
Reporter: Michael | Owner: nobody
Type: Uncategorized | Status: new
Component: contrib.staticfiles | Version: 5.0
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-----------------------------------------------+------------------------
This regex from django/contrib/staticfiles/storage.py -> HashedFilesMixin
-> _js_module_import_aggregation_patterns:
{{{
(
(
r"""(?P<matched>export(?s:(?P<exports>[\s\{].*?))"""
r"""\s*from\s*["'](?P<url>[./].*?)["']\s*;)"""
),
"""export%(exports)s from "%(url)s";""",
),
}}}
Can result in a matchobj like this:
{{{
> /home/michael/.venv/project/lib/python3.11/site-
packages/django/contrib/staticfiles/storage.py(225)converter()
(Pdb) pp
matchobj.re
re.compile('(?P<matched>export(?s:(?P<exports>[\\s\\{].*?))\\s*from\\s*["\'](?P<url>[./].*?)["\']\\s*;)',
re.IGNORECASE)
(Pdb) pp matchobj.groupdict()
{'exports': ' async function getTakeMessageDialog(a,t={}){const '
'e=f();e.toggleAttribute("top",!0);const '
'i=document.createElement("wc-take-
message");for(i.toggleAttribute("caneditcontacts",a),t&&(i.props=t),e.appendChild(i),e.save(null,{heading:"Take
'
'a Message",confirm:"Submit"}),i.focus();;){if(!await '
'e.waitClickedAction())return;if(!i.validate())continue;const
'
'n=await '
'c.createTakeMessage(i.props);if(n.ok){e.close(),n.notifySuccess("Message
'
'taken");return}}}import w',
'matched': 'export async function getTakeMessageDialog(a,t={}){const '
'e=f();e.toggleAttribute("top",!0);const '
'i=document.createElement("wc-take-
message");for(i.toggleAttribute("caneditcontacts",a),t&&(i.props=t),e.appendChild(i),e.save(null,{heading:"Take
'
'a Message",confirm:"Submit"}),i.focus();;){if(!await '
'e.waitClickedAction())return;if(!i.validate())continue;const
'
'n=await '
'c.createTakeMessage(i.props);if(n.ok){e.close(),n.notifySuccess("Message
'
'taken");return}}}import w from '
'"/static/skin/skin/x-field.min.c6fe58e9f403.css";',
'url': '/static/skin/skin/x-field.min.c6fe58e9f403.css'}
(Pdb) matchobj.string
'var l=Object.defineProperty;var p=(a,t,e)=>t in
a?l(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var
o=(a,t,e)=>(p(a,typeof t!="symbol"?t+"":t,e),e);import*as r
from"/static/jsapp/jsapp/dtmod.min.js";import*as c
from"/static/comms/jsapp/fetcher.min.js";import*as g
from"/static/jsapp/jsapp/ui.min.js";import*as m
from"/static/jsapp/jsapp/formmod.min.js";import{createDialog as f} from
"/static/wcapp/wcapp/wc-dialog.min.2f89ad88aab3.js";import{BaseComponent
as h} from "/static/wcapp/jsapp/wc-base.min.425310100bce.js";class d
extends
h{init(){g.setupAutoHeight(this.get("MESSAGE")),this.initProps(!1)}setupEvents(){this.get("EDIT").onclick=this.setEditMode.bind(this,!0),this.get("CANCEL").onclick=this.setEditMode.bind(this,!1),this.get("SAVE").onclick=async()=>{if(!this.validate())return;(await
c.updateTakeMessage(this._
props.id,this.props)).ok&&this.setEditMode(!1)}}setEditMode(t){this.toggleAttribute("disabled",!t)}setNoAddContact(){const
t=this.get("SEL_ADD_CONTACT").checked;this.toggleAttribute("noaddcontact",!t)}selectContactHandler(t){var
e;((e=t.target)==null?void
0:e.getAttribute("name"))==="select_contact"&&this.setNoAddContact()}attributeChangedCallback(t,e,i){switch(t){case"disabled":this.setDisabled(i!==null);break}}set
props(t){console.log(t),this._props=t;for(const e of
Object.keys(t))switch(e){case"message":this.get("MESSAGE").value=t[e];break;case"createdUtc":this.get("TAKEN_AT").innerHTML=r.formatIsoStr(t[e],r.SHORT_DATETIME);break;case"userName":this.get("TAKEN_BY").innerHTML=t[e];break;case"recipientName":this.get("TAKEN_FOR").innerHTML=t[e];break;case"clientName":const
i=t[e];t.client||(this.get("CLIENT_NAME").value=t[e],this.get("CLIENT_NAME").toggleAttribute("required",!0),this.get("CLIENT_NAME_LABEL").classList.remove("d:n"));break;case"client":const
s=t[e];s&&(this.get("BADGE").props=s,this.get("BADGE").classList.remove("d:n"));break;case"contact":this.get("CONTACT").props=t[e]}}get
props(){var i;return{client:(i=this._props.client)==null?void
0:
i.id,clientName:this.get("CLIENT_NAME").value,message:this.get("MESSAGE").value,contact:this.get("CONTACT").props}}setDisabled(t){this.get("CONTACT").disabled=t,this.get("MESSAGE").disabled=t,this.get("CLIENT_NAME").disabled=t}validate(){const
t=["CONTACT","MESSAGE"].map(e=>this.get(e));return
this.get("CLIENT_NAME").classList.contains("d:n")||t.push(this.get("CLIENT_NAME")),m.manualClientValidation(t)}}o(d,"observedAttributes",["disabled"]),o(d,"properties",["props"]);export
async function getTakeMessageDialog(a,t={}){const
e=f();e.toggleAttribute("top",!0);const i=document.createElement("wc-take-
message");for(i.toggleAttribute("caneditcontacts",a),t&&(i.props=t),e.appendChild(i),e.save(null,{heading:"Take
a Message",confirm:"Submit"}),i.focus();;){if(!await
e.waitClickedAction())return;if(!i.validate())continue;const n=await
c.createTakeMessage(i.props);if(n.ok){e.close(),n.notifySuccess("Message
taken");return}}}import w from
"/static/skin/skin/x-field.min.c6fe58e9f403.css";import u from
"/static/common/skin/cfm-heading.min.b8e21816b92c.css";const
b=[w,u];d.initComponent(String.raw`<div id="MAIN" class="d:f f-d:c
g:--gap"><div id="TAKEN_TABLE" class="d:g (w>768)g-t-c:repeat(6,auto)
(w<768)g-t-c:auto_auto w:f-c g:8"><div x-field="label">By</div><div
id="TAKEN_BY" class="m-r:16"></div><div x-field="label">At</div><div
id="TAKEN_AT" class="m-r:16"></div><div x-field="label">For</div><div
id="TAKEN_FOR"></div></div><div cfm-heading>Client</div><label
id="CLIENT_NAME_LABEL" for="CLIENT_NAME" class="d:n d:f? a-i:c f-w:w
g:8px_16px"><div x-field="label">Client Name</div><input id="CLIENT_NAME"
x-field="widget tonal stadium" type="text" disabled></label><wc-badge
id="BADGE" class="d:n w:256 max-w:100%"></wc-badge><div cfm-
heading>Contact</div><wc-contact disabled id="CONTACT"></wc-contact><div
class="d:f g:--gap f-w:w"><div class="d:f f-d:c g:--gap f-g:15"><label
cfm-heading for="MESSAGE">Message</label><textarea id="MESSAGE" rows="4"
x-field="widget tonal stadium" class="f-g:1" required disable-if-
disabled></textarea></div></div><div class="f-s:i c:--red" show-if-
enabled>Please note:<br>The recipient will not be notified or emailed
again, and any memo\'s or contacts that were originally created from the
message will remain as is.</div><div class="d:f? m-t:16 j-c:e a-i:c f-w:w
g:16px_16px" show-if-canedit><wc-button id="EDIT" type="tonal"
color="primary" show-if-disabled>EDIT</wc-button><wc-button id="CANCEL"
type="tonal" color="bw" class="min-w:92" show-if-enabled>CANCEL</wc-
button><wc-button id="SAVE" type="solid" color="secondary"
class="min-w:92" show-if-enabled>SAVE</wc-
button></div></div>\n`,String.raw`:host{display:block}\n*,*:before,*:after
{box-sizing:border-box}\n::selection{color:var(--selection-fg,
white);background:var(--selection-bg, #888)}\nsvg{vertical-
align:bottom}\nsvg,img[src$=".svg"]{flex-shrink:0}\ntextarea{font-
family:inherit}\n.a-i\\:c{align-
items:center!important}\n.c\\:--red{color:var(--red)!important}\n.d\\:f{display:flex!important}\n.d\\:f\\?{display:flex}\n.d\\:g{display:grid!important}\n.d\\:n{display:none!important}\n.f-d\\:c
{flex-direction:column!important}\n.f-g\\:1{flex-
grow:1!important}\n.f-g\\:15{flex-grow:15!important}\n.f-s\\:i{font-
style:italic!important}\n.f-w\\:w{flex-
wrap:wrap!important}\n.g\\:--gap{gap:var(--gap)!important}\n.g\\:16px_16px{gap:16px
16px!important}\n.g\\:8{gap:8px!important}\n.g\\:8px_16px{gap:8px
16px!important}\n.j-c\\:e{justify-content:end!important}\n.m-r\\:16
{margin-right:16px!important}\n.m-t\\:16{margin-
top:16px!important}\n.max-w\\:100\\%{max-
width:100%!important}\n.min-w\\:92{min-
width:92px!important}\n.w\\:256{width:256px!important}\n.w\\:f-c{width
:fit-content!important}\n@media (max-
width:767.999px){.\\(w\\<768\\)g-t-c\\:auto_auto{grid-template-
columns:auto auto!important}}\n@media (min-
width:768.001px){.\\(w\\>768\\)g-t-c\\:repeat\\(6\\,auto\\){grid-template-
columns:repeat(6,auto)!important}}\n:host{display:grid;grid-template-
columns:minmax(100%,1024px)}\n:host(:not([disabled])) [show-if-
disabled]{display:none!important}\n:host([disabled]) [show-if-
enabled]{display:none!important}\n:host(:not([canedit])) [show-if-
canedit]{display:none!important}\n`,b,"wc-message-taken",["wc-button","wc-
select-client","wc-contact","wc-modal"]);\n'
}}}
From this Javascript file:
{{{
var r=Object.defineProperty;var p=(n,t,e)=>t in
n?r(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var
c=(n,t,e)=>(p(n,typeof t!="symbol"?t+"":t,e),e);import*as d
from"/static/comms/jsapp/fetcher.min.js";import*as h
from"/static/jsapp/jsapp/ui.min.js";import*as g
from"/static/jsapp/jsapp/formmod.min.js";import{createDialog as
f}from"/static/wcapp/wcapp/wc-dialog.min.js";import{BaseComponent as
u}from"/static/wcapp/jsapp/wc-base.min.js";class l extends
u{init(){this._setupPromise=this.setupContext(),h.setupAutoHeight(this.get("MESSAGE")),this.initProps(!1)}setupEvents(){this.get("SELECT_CLIENT").addEventListener("clientChanged",this.changeClientHandler.bind(this)),this.get("SELECT_CLIENT").addEventListener("clientCleared",this.clientClearedHandler.bind(this)),this.get("CONTACTS").addEventListener("click",this.clickButtonHandler.bind(this)),this.get("CONTACTS").addEventListener("change",this.selectContactHandler.bind(this))}setNoAddContact(){const
t=this.get("SEL_ADD_CONTACT").checked;this.toggleAttribute("noaddcontact",!t)}selectContactHandler(t){var
e;((e=t.target)==null?void
0:e.getAttribute("name"))==="select_contact"&&this.setNoAddContact()}attributeChangedCallback(t,e,i){switch(t){case"disabled":this.setDisabled(i!==null);break}}set
props(t){this._props=t}get props(){const
t=this.getAttribute("clientid");return{...this._props,client:t?parseInt(t):null,clientName:t?null:this.get("SELECT_CLIENT").pattern,recipient:parseInt(this.get("RECIPIENT").value),message:this.get("MESSAGE").value,contact:this.querySelectedContactEl().props,createMemo:this.get("CREATE_MEMO").checked,addContact:this.get("ADD_CONTACT").checked}}async
setupContext(){this._context||(this._context=await
this.getContext(),this.buildEmployees(this._context.employees),this.buildClients(this._context.clients))}async
buildEmployees(t){if(this.get("RECIPIENT").firstElementChild)return;const
e=t.map(s=>{const a=document.createElement("option");return
a.value=
s.pk,a.innerText=s.fullName,a});this.get("RECIPIENT").replaceChildren(...e);const
i=Math.min(e.length,10);!this.hasAttribute("disabled")&&!this.hasAttribute("update")&&this.get("RECIPIENT").setAttribute("size",i),this.get("RECIPIENT").setAttribute("sizebak",i)}async
buildClients(t){this.get("SELECT_CLIENT").props=t}async
getContext(){if(this._context)return this._context;const t=await
d.getContext();if(t.ok)return
this._context=t.json,this._context}setDisabled(t){this.shadowRoot.querySelectorAll
("[disable-if-
disabled]").forEach(i=>i.toggleAttribute("disabled",t)),this.hasAttribute("update")&&this.get("RECIPIENT").toggleAttribute("disabled",!0);const
e=this.get("RECIPIENT");this.get("RECIPIENT").hasAttribute("disabled")?e.removeAttribute("size"):e.setAttribute("size",e.getAttribute("sizebak"))}cloneChild(t,e){const
i=this.get("CONTACT_TEMPLATE").content.cloneNode(!0).firstElementChild,s=i.querySelector
("wc-contact");s.props=t;const
a=i.querySelector('[name="select_contact"]'),o=i.querySelector("label");return
a.id=`contact_${t.hash}`,o.setAttribute("for",
a.id),s.disabled=!0,i}getContactOptions(){return
this._contactOptions}selectContact(t){const
e=this.get("CONTACTS").querySelector(`[data-hash="${t}"]`),i=e==null?void
0:e.querySelector('[name="contact"]');i&&(i.checked=!0)}setContact(t){t.hash?this.selectContact(t.hash):(this.get("NEW_CONTACT").props=t,this.get("ADD_CONTACT").checked=!0)}setContacts(t){this._contactOptions=t||[];const
e=this._contactOptions.map((i,s)=>this.cloneChild(i,s));this.get("CONTACTS_SLOT").replaceChildren(...e)}setExistingClient(t){t?this.setAttribute("clientid",t):this.removeAttribute("clientid"),t||(this.get("SEL_ADD_CONTACT").checked=!0),t||(this.get("ADD_CONTACT").checked=!1),this.get("MESSAGE").autoHeight()}changeClientHandler(t){const
e=t.detail.props;this.setExistingClient(e==null?void 0:
e.id);const
i=(e==null?void
0:e.hashedContacts)||[];this.setContacts(i)}enableEditContact(t,e){const
i=e.querySelector("wc-contact");i.disabled=!t,e.querySelector('[data-
button="edit"]').classList.toggle("d:n",t),e.querySelector('[data-
button="cancel"]').classList.toggle("d:n",!t),e.querySelector('[data-
button="save"]').classList.toggle("d:n",!t)}clickButtonHandler(t){const
e=t.target.getAttribute("data-
button");if(!e)return;t.stopPropagation();const i=t.target.closest(".js-
main");switch(e){case"edit":this.enableEditContact(!0,i);break;case"cancel":this.enableEditContact(!1,i);break;case"save":this.updateContact(i);break}}clientClearedHandler(){this.setExistingClient(!1),this.setContacts([]),this.setNoAddContact()}querySelectedMainEl(){return
this.get("CONTACTS").querySelector('[name="select_contact"]:checked').closest
(".js-main")}querySelectedContactEl(){return
this.querySelectedMainEl().querySelector("wc-
contact")}focus(){this.get("SELECT_CLIENT").focus()}validate(){const
t=["SELECT_CLIENT","RECIPIENT","MESSAGE"].map(e=>this.get(e));return
g.manualClientValidation(t)}async updateContact(t){const
e=parseInt(this.getAttribute("clientid")),i=t.querySelector("wc-
contact"),a={contact:i.props},o=await
d.clientUpdateContact(e,a);o.ok&&(this.enableEditContact(!1,t),i.props={...i.props,hash:o.json.newHash})}}c(l,"observedAttributes",["disabled"]),c(l,"properties",["props"]);export
async function getTakeMessageDialog(n,t={}){const
e=f();e.toggleAttribute("top",!0);const i=document.createElement("wc-take-
message");for(i.toggleAttribute("caneditcontacts",n),t&&(i.props=t),e.appendChild(i),e.save(null,{heading:"Take
a Message",confirm:"Submit"}),i.focus();;){if(!await
e.waitClickedAction())return;if(!i.validate())continue;const a=await
d.createTakeMessage(i.props);if(a.ok){e.close(),setTimeout(()=>a.notifySuccess("Message
taken"),100);return}}}import m
from"/static/skin/skin/x-field.min.css";import C from"/static/common/skin
/cfm-heading.min.css";const b=[m,C];l.initComponent(String.raw`<div
id="MAIN" class="d:f f-d:c g:--gap"><wc-select-client id="SELECT_CLIENT"
newtab selectable sel1stsearch patternisnonelabel disable-if-disabled
></wc-select-client><div cfm-heading>Contact</div><div id="CONTACTS"
class="d:f f-d:c"><div class="js-main d:f a-i:c g:8px_16px f-g:1"><input
id="SEL_ADD_CONTACT" x-field="widget" type="radio" name="select_contact"
value="new" checked show-if-clientid><div class="d:f f-d:c g:8
f-g:1"><label for="SEL_ADD_CONTACT" class="f-w:500" show-if-clientid>New
Contact</label><wc-contact id="NEW_CONTACT" class="f-g:1" show-if-
addcontact disable-if-disabled></wc-contact><label for="ADD_CONTACT"
class="d:f g:8 w:f-c m-y:4" show-if-clientid show-if-addcontact show-if-
caneditcontacts><input id="ADD_CONTACT" type="checkbox" x-field="widget"
disable-if-disabled><div title="If the client exists, it will be updated
with this info">Add this contact to the
client?</div></label></div></div><slot id="CONTACTS_SLOT"
name="contacts"></slot></div><div class="d:f g:--gap f-w:w"><div
class="d:f f-d:c g:--gap f-g:10" hide-if-disabled><div cfm-
heading>Notify</div><select id="RECIPIENT" x-field="widget tonal stadium"
class="o-y:v max-h:640" disable-if-disabled required></select></div><div
class="d:f f-d:c g:--gap f-g:15"><label cfm-heading
for="MESSAGE">Message</label><textarea id="MESSAGE" rows="4"
x-field="widget tonal stadium" class="f-g:1" required disable-if-
disabled></textarea><label for="CREATE_MEMO" class="d:f g:8 (w<640)m-y:8"
hide-if-disabled show-if-clientid><input id="CREATE_MEMO" type="checkbox"
x-field="widget" disable-if-disabled><div class="js-save-action"
title="Also create a Client Memo that corresponds to this message">Also
create a Client Memo?</div></label></div></div></div><template
id="CONTACT_TEMPLATE"><div class="js-main d:f a-i:c j-c:e c-g:24 r-g:8
f-w:w"><div class="d:f a-i:c g:8px_16px f-g:10000"><input x-field="widget"
type="radio" x-field="widget" name="select_contact" disable-if-
disabled><label x-field="label" class="f-g:1" hide-if-disabled><wc-contact
></wc-contact></label></div><div class="d:f a-i:c f-w:w (w>530)f-d:c
g:16px_16px" hide-if-disabled show-if-caneditcontacts><wc-button
type="tonal" color="primary" data-button="edit">EDIT</wc-button><wc-
button type="text" color="bw" data-button="cancel" class="min-w:92
d:n">CANCEL</wc-button><wc-button type="solid" color="secondary" data-
button="save" class="min-w:92 d:n">SAVE</wc-
button></div></div></template>
`,String.raw`styles`,b,"wc-take-message",[]);
}}}
Which means collect static fails:
{{{
Post-processing 'comms/wcapp/wc-take-message.min.js' failed!
Traceback (most recent call last):
File "/home/michael/project/src/manage.py", line 57, in <module>
run()
File "/home/michael/project/src/manage.py", line 49, in run
execute_from_command_line(sys.argv)
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/core/management/__init__.py", line 442, in
execute_from_command_line
utility.execute()
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/core/management/__init__.py", line 436, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/core/management/base.py", line 413, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/core/management/base.py", line 459, in execute
output = self.handle(*args, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/michael/project/src/core/app/base/management/commands/deploy.py",
line 84, in handle
call_command('collectstatic', '--noinput', '--clear', '--verbosity',
'0')
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/core/management/__init__.py", line 194, in call_command
return command.execute(*args, **defaults)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/core/management/base.py", line 459, in execute
output = self.handle(*args, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/contrib/staticfiles/management/commands/collectstatic.py",
line 209, in handle
collected = self.collect()
^^^^^^^^^^^^^^
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/contrib/staticfiles/management/commands/collectstatic.py",
line 154, in collect
raise processed
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/contrib/staticfiles/storage.py", line 375, in
_post_process
content = pattern.sub(converter, content)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/contrib/staticfiles/storage.py", line 249, in converter
hashed_url = self._url(
^^^^^^^^^^
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/contrib/staticfiles/storage.py", line 182, in _url
hashed_name = hashed_name_func(*args)
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/contrib/staticfiles/storage.py", line 425, in _stored_name
cache_name = self.clean_name(self.hashed_name(name))
^^^^^^^^^^^^^^^^^^^^^^
File "/home/michael/.venv/project/lib/python3.11/site-
packages/django/contrib/staticfiles/storage.py", line 143, in hashed_name
raise ValueError(
ValueError: The file 'skin/skin/x-field.min.c6fe58e9f403.css' could not be
found with <base.storage.LcManifestStaticFilesStorage object at
0x7f645c578a10>.
}}}
Even though the file exists in the correct collect static spot:
{{{
:/var/www/
example.com/public/static/skin/skin$ ls -la x-field.min.css
-rw-r--r-- 1 michael www-data 6387 Apr 12 08:07 x-field.min.css
}}}
--
Ticket URL: <
https://code.djangoproject.com/ticket/35371>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.