fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

788
node_modules/@wordpress/scripts/LICENSE.md generated vendored Normal file
View File

@@ -0,0 +1,788 @@
## Gutenberg
Copyright 2016-2024 by the contributors
**License for Contributions (on and after April 15, 2021)**
All code contributed to the Gutenberg project is dual-licensed,
and released under both of the following licenses:
the GNU General Public License as published by the Free Software Foundation;
either version 2 of the License or (at your option) any later version (the “GPL”)
and the Mozilla Public License, Version 2.0 (the “MPL”).
**Project License**
The Gutenberg project license is not affected by the License for Contributions (as
discussed in the [Dual License section](#dual-license) below). The Gutenberg project
continues to be free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License or (at your option) any
later version (the “GPL”).
This program incorporates work covered by the following copyright and
permission notices:
b2 is (c) 2001, 2002 Michel Valdrighi - m@tidakada.com -
http://tidakada.com
Wherever third party code has been used, credit has been given in the code's
comments.
b2 is released under the GPL
and
WordPress - Web publishing software
Copyright 2003-2010 by the contributors
WordPress is released under the GPL
### Dual License
**We are currently in the process of changing Gutenbergs software license from
GPL to a dual license: GPL and MPL.**
**This process involves two independent steps (1) obtaining permission for dual
licensing from contributors of already contributed Gutenberg code and (2)
dual licensing of all contributions to Gutenberg that are made on or after
April 15, 2021.**
**For part (1): Were reaching out to everyone who has contributed code, prior
to April 15, 2021, and asking that they agree to dual license their
contribution to the project. We expect this process to be completed by
mid-year, 2021.**
**For part (2): We have changed the license for contributed code to this
repository to make clear that all contributions on or after April 15, 2021
will be made under the dual-license.**
**When we have received all necessary rights and permissions to dual license
the pre-April 15, 2021 code of the Gutenberg project (Part 1 above), you will
have the option to use and distribute all of the Gutenberg project under
either the GPL or MPL license. At this time we will change the “Project
License” to the following:**
The Gutenberg project is free software; you can redistribute it and/or modify
it under the terms of either of the following licenses:
1. the GNU General Public License as published by the Free Software Foundation;
either version 2 of the License or (at your option) any later version (the
“GPL”) OR
2. the Mozilla Public License Version 2.0 (the “MPL”).
---
## Full Text of Referenced Licenses
1. [GNU General Public License, Version 2](#gnu-general-public-license-version-2)
2. [Mozilla Public License, Version 2.0](#mozilla-public-license-version-20)
## GNU General Public License, Version 2
### GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
### Preamble
The licenses for most software are designed to take away your freedom
to share and change it. By contrast, the GNU General Public License is
intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on,
we want its recipients to know that what they have is not the
original, so that any problems introduced by others will not reflect
on the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at
all.
The precise terms and conditions for copying, distribution and
modification follow.
### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
**0.** This License applies to any program or other work which
contains a notice placed by the copyright holder saying it may be
distributed under the terms of this General Public License. The
"Program", below, refers to any such program or work, and a "work
based on the Program" means either the Program or any derivative work
under copyright law: that is to say, a work containing the Program or
a portion of it, either verbatim or with modifications and/or
translated into another language. (Hereinafter, translation is
included without limitation in the term "modification".) Each licensee
is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the Program
(independent of having been made by running the Program). Whether that
is true depends on what the Program does.
**1.** You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a
fee.
**2.** You may modify your copy or copies of the Program or any
portion of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
**a)** You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
**b)** You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any part
thereof, to be licensed as a whole at no charge to all third parties
under the terms of this License.
**c)** If the modified program normally reads commands interactively
when run, you must cause it, when started running for such interactive
use in the most ordinary way, to print or display an announcement
including an appropriate copyright notice and a notice that there is
no warranty (or else, saying that you provide a warranty) and that
users may redistribute the program under these conditions, and telling
the user how to view a copy of this License. (Exception: if the
Program itself is interactive but does not normally print such an
announcement, your work based on the Program is not required to print
an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
**3.** You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
**a)** Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections 1
and 2 above on a medium customarily used for software interchange; or,
**b)** Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your cost of
physically performing source distribution, a complete machine-readable
copy of the corresponding source code, to be distributed under the
terms of Sections 1 and 2 above on a medium customarily used for
software interchange; or,
**c)** Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is allowed
only for noncommercial distribution and only if you received the
program in object code or executable form with such an offer, in
accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
**4.** You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt otherwise
to copy, modify, sublicense or distribute the Program is void, and
will automatically terminate your rights under this License. However,
parties who have received copies, or rights, from you under this
License will not have their licenses terminated so long as such
parties remain in full compliance.
**5.** You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
**6.** Each time you redistribute the Program (or any work based on
the Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
**7.** If, as a consequence of a court judgment or allegation of
patent infringement or for any other reason (not limited to patent
issues), conditions are imposed on you (whether by court order,
agreement or otherwise) that contradict the conditions of this
License, they do not excuse you from the conditions of this License.
If you cannot distribute so as to satisfy simultaneously your
obligations under this License and any other pertinent obligations,
then as a consequence you may not distribute the Program at all. For
example, if a patent license would not permit royalty-free
redistribution of the Program by all those who receive copies directly
or indirectly through you, then the only way you could satisfy both it
and this License would be to refrain entirely from distribution of the
Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
**8.** If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
**9.** The Free Software Foundation may publish revised and/or new
versions of the General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Program does not specify a
version number of this License, you may choose any version ever
published by the Free Software Foundation.
**10.** If you wish to incorporate parts of the Program into other
free programs whose distribution conditions are different, write to
the author to ask for permission. For software which is copyrighted by
the Free Software Foundation, write to the Free Software Foundation;
we sometimes make exceptions for this. Our decision will be guided by
the two goals of preserving the free status of all derivatives of our
free software and of promoting the sharing and reuse of software
generally.
**NO WARRANTY**
**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
### END OF TERMS AND CONDITIONS
### How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
one line to give the program's name and an idea of what it does.
Copyright (C) yyyy name of author
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Also add information on how to contact you by electronic and paper
mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
type `show w'. This is free software, and you are welcome
to redistribute it under certain conditions; type `show c'
for details.
The hypothetical commands \`show w' and \`show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than \`show w' and
\`show c'; they could even be mouse-clicks or menu items--whatever
suits your program.
You should also get your employer (if you work as a programmer) or
your school, if any, to sign a "copyright disclaimer" for the program,
if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright
interest in the program `Gnomovision'
(which makes passes at compilers) written
by James Hacker.
signature of Ty Coon, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library,
you may consider it more useful to permit linking proprietary
applications with the library. If this is what you want to do, use the
[GNU Lesser General Public
License](http://www.gnu.org/licenses/lgpl.html) instead of this
License.
---
## Mozilla Public License, Version 2.0
### 1. Definitions
**1.1. “Contributor”**
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
**1.2. “Contributor Version”**
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
**1.3. “Contribution”**
means Covered Software of a particular Contributor.
**1.4. “Covered Software”**
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
**1.5. “Incompatible With Secondary Licenses”**
means
- **(a)** that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
- **(b)** that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
**1.6. “Executable Form”**
means any form of the work other than Source Code Form.
**1.7. “Larger Work”**
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
**1.8. “License”**
means this document.
**1.9. “Licensable”**
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
**1.10. “Modifications”**
means any of the following:
- **(a)** any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
- **(b)** any new file in Source Code Form that contains any Covered
Software.
**1.11. “Patent Claims” of a Contributor**
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
**1.12. “Secondary License”**
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
**1.13. “Source Code Form”**
means the form of the work preferred for making modifications.
**1.14. “You” (or “Your”)**
means an individual or a legal entity exercising rights under this
License. For legal entities, “You” includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, “control” means **(a)** the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or **(b)** ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
### 2. License Grants and Conditions
#### 2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
- **(a)** under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
- **(b)** under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
#### 2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
#### 2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
- **(a)** for any code that a Contributor has removed from Covered Software;
or
- **(b)** for infringements caused by: **(i)** Your and any other third party's
modifications of Covered Software, or **(ii)** the combination of its
Contributions with other software (except as part of its Contributor
Version); or
- **(c)** under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
#### 2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
#### 2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
#### 2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
#### 2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
### 3. Responsibilities
#### 3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
#### 3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
- **(a)** such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
- **(b)** You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
#### 3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
#### 3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
#### 3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
### 4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: **(a)** comply with
the terms of this License to the maximum extent possible; and **(b)**
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
### 5. Termination
**5.1.** The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated **(a)** provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and **(b)** on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
**5.2.** If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
### 6. Disclaimer of Warranty
> Covered Software is provided under this License on an “as is”
> basis, without warranty of any kind, either expressed, implied, or
> statutory, including, without limitation, warranties that the
> Covered Software is free of defects, merchantable, fit for a
> particular purpose or non-infringing. The entire risk as to the
> quality and performance of the Covered Software is with You.
> Should any Covered Software prove defective in any respect, You
> (not any Contributor) assume the cost of any necessary servicing,
> repair, or correction. This disclaimer of warranty constitutes an
> essential part of this License. No use of any Covered Software is
> authorized under this License except under this disclaimer.
### 7. Limitation of Liability
> Under no circumstances and under no legal theory, whether tort
> (including negligence), contract, or otherwise, shall any
> Contributor, or anyone who distributes Covered Software as
> permitted above, be liable to You for any direct, indirect,
> special, incidental, or consequential damages of any character
> including, without limitation, damages for lost profits, loss of
> goodwill, work stoppage, computer failure or malfunction, or any
> and all other commercial damages or losses, even if such party
> shall have been informed of the possibility of such damages. This
> limitation of liability shall not apply to liability for death or
> personal injury resulting from such party's negligence to the
> extent applicable law prohibits such limitation. Some
> jurisdictions do not allow the exclusion or limitation of
> incidental or consequential damages, so this exclusion and
> limitation may not apply to You.
### 8. Litigation
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
### 9. Miscellaneous
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
### 10. Versions of the License
#### 10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
#### 10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
#### 10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
## Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
## Exhibit B - “Incompatible With Secondary Licenses” Notice
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

745
node_modules/@wordpress/scripts/README.md generated vendored Normal file
View File

@@ -0,0 +1,745 @@
# Scripts
This is a collection of reusable scripts tailored for WordPress development. For convenience, every tool provided in this package comes with an integrated recommended configuration.
When working seamlessly, sophisticated command-line interfaces help to turn work with a project into a more pleasant experience. However, its a misleading assumption that developers can easily pick the proper tools in the first place and then ensure that they play along with each other, including all their extensions. Besides, its still not enough because developers are left on their own to keep all configurations and dependent tools up to date. This problem multiplies when they support more than one project which shares the same setup.
Fortunately, there is a pattern that can simplify maintainers life reusable scripts. The idea boils down to moving all the necessary configurations and scripts to one single tool dependency. In most cases, it should be possible to accomplish all tasks using the default settings, but some customization is allowed, too. With all that in place, updating all projects should become a very straightforward task.
_This package is inspired by [react-scripts](https://www.npmjs.com/package/react-scripts) and [kcd-scripts](https://www.npmjs.com/package/kcd-scripts)._
## Installation
You only need to install one npm module:
```bash
npm install @wordpress/scripts --save-dev
```
**Note**: This package requires Node.js 14.0.0 or later, and `npm` 6.14.4 or later. It is not compatible with older versions.
## Setup
This package offers a command-line interface and exposes a binary called `wp-scripts` so you can call it directly with `npx` an npm package runner. However, this module is designed to be configured using the `scripts` section in the `package.json` file of your project. This comprehensive example demonstrates the most of the capabilities included.
_Example:_
```json
{
"scripts": {
"build": "wp-scripts build",
"check-engines": "wp-scripts check-engines",
"check-licenses": "wp-scripts check-licenses",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"lint:md:docs": "wp-scripts lint-md-docs",
"lint:pkg-json": "wp-scripts lint-pkg-json",
"packages-update": "wp-scripts packages-update",
"plugin-zip": "wp-scripts plugin-zip",
"start": "wp-scripts start",
"test:e2e": "wp-scripts test-e2e",
"test:unit": "wp-scripts test-unit-js"
}
}
```
It might also be a good idea to get familiar with the [JavaScript Build Setup tutorial](https://github.com/WordPress/gutenberg/tree/HEAD/docs/how-to-guides/javascript/js-build-setup.md) for setting up a development environment to use ESNext syntax. It gives a very in-depth explanation of how to use the [build](#build) and [start](#start) scripts.
## Automatic block.json detection and the source code directory
When using the `start` or `build` commands, the source code directory ( the default is `./src`) and its subdirectories are scanned for the existence of `block.json` files. If one or more are found, they are treated a entry points and will be output into corresponding folders in the `build` directory. This allows for the creation of multiple blocks that use a single build process. The source directory can be customized using the `--webpack-src-dir` flag and the output directory with the `--output-path` flag.
## Updating to New Release
To update an existing project to a new version of `@wordpress/scripts`, open the [changelog](https://github.com/WordPress/gutenberg/blob/HEAD/packages/scripts/CHANGELOG.md), find the version youre currently on (check `package.json` in the top-level directory of your project), and apply the migration instructions for the newer versions.
In most cases bumping the `@wordpress/scripts` version in `package.json` and running `npm install` in the root folder of your project should be enough, but its good to check the [changelog](https://github.com/WordPress/gutenberg/blob/HEAD/packages/scripts/CHANGELOG.md) for potential breaking changes. There is also `packages-update` script included in this package that aims to automate the process of updating WordPress dependencies in your projects.
We commit to keeping the breaking changes minimal so you can upgrade `@wordpress/scripts` as seamless as possible.
## Available Scripts
### `build`
Transforms your code according the configuration provided so its ready for production and optimized for the best performance.
_This script exits after producing a single build. For incremental builds, better suited for development, see the [start](#start) script._
The entry points for your project get detected by scanning all script fields in `block.json` files located in the `src` directory. The script fields in `block.json` should pass relative paths to `block.json` in the same folder.
_Example:_
```json
{
"editorScript": "file:index.js",
"script": "file:script.js",
"viewScript": "file:view.js"
}
```
The fallback entry point is `src/index.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) in case there is no `block.json` file found. In that scenario, the output generated will be written to `build/index.js`.
_Example:_
```json
{
"scripts": {
"build": "wp-scripts build",
"build:custom": "wp-scripts build entry-one.js entry-two.js --output-path=custom",
"build:copy-php": "wp-scripts build --webpack-copy-php",
"build:custom-directory": "wp-scripts build --webpack-src-dir=custom-directory"
}
}
```
This is how you execute the script with presented setup:
- `npm run build` - builds the code for production.
- `npm run build:custom` - builds the code for production with two entry points and a custom output directory. Paths for custom entry points are relative to the project root.
- `npm run build:copy-php` - builds the code for production and opts into copying all PHP files from the `src` directory and its subfolders to the output directory. By default, only PHP files listed in the `render` field in the detected `block.json` files get copied.
- `npm run build:custom-directory` - builds the code for production using the `custom-directory` as the source code directory.
This script automatically use the optimized config but sometimes you may want to specify some custom options:
- `--webpack-bundle-analyzer` enables visualization for the size of webpack output files with an interactive zoomable treemap.
- `--webpack-copy-php` enables copying all PHP files from the source directory ( default is `src` ) and its subfolders to the output directory.
- `--webpack-no-externals` disables scripts' assets generation, and omits the list of default externals.
- `--webpack-src-dir` Allows customization of the source code directory. Default is `src`.
- `--output-path` Allows customization of the output directory. Default is `build`.
Experimental support for the block.json `viewScriptModule` field is available via the
`--experimental-modules` option. With this option enabled, script and module fields will all be
compiled. The `viewScriptModule` field is analogous to the `viewScript` field, but will compile a module
and should be registered in WordPress using the Modules API.
#### Advanced information
This script uses [webpack](https://webpack.js.org/) behind the scenes. Itll look for a webpack config in the top-level directory of your package and will use it if it finds one. If none is found, itll use the default config provided by `@wordpress/scripts` packages. Learn more in the [Advanced Usage](#advanced-usage) section.
### `check-engines`
Checks if the current `node`, `npm` (or `yarn`) versions match the given [semantic version](https://semver.org/) ranges. If the given version is not satisfied, information about installing the needed version is printed and the program exits with an error code.
_Example:_
```json
{
"scripts": {
"check-engines": "wp-scripts check-engines"
}
}
```
This is how you execute the script with presented setup:
- `npm run check-engines` - checks installed version of `node` and `npm`.
#### Advanced information
It uses [check-node-version](https://www.npmjs.com/package/check-node-version) behind the scenes with the recommended configuration provided. The default requirements are set to the same Node.js and npm versions as listed in the [installation](#installation) section for this package. You can specify your own ranges as described in [check-node-version docs](https://www.npmjs.com/package/check-node-version). Learn more in the [Advanced Usage](#advanced-usage) section.
### `check-licenses`
Validates that all dependencies of a project are compatible with the projects own license.
_Example:_
```json
{
"scripts": {
"check-licenses": "wp-scripts check-licenses --prod --gpl2 --ignore=abab"
}
}
```
_Flags_:
- `--prod` (or `--production`): When present, validates only `dependencies` and not `devDependencies`
- `--dev` (or `--development`): When present, validates only `devDependencies` and not `dependencies`
- `--gpl2`: Validates against [GPLv2 license compatibility](https://www.gnu.org/licenses/license-list.en.html)
- `--ignore=a,b,c`: A comma-separated set of package names to ignore for validation. This is intended to be used primarily in cases where a dependencys `license` field is malformed. Its assumed that any `ignored` package argument would be manually vetted for compatibility by the project owner.
### `format`
It helps to enforce coding style guidelines for your files (enabled by default for JavaScript, JSON, TypeScript, YAML) by formatting source code in a consistent way.
_Example:_
```json
{
"scripts": {
"format": "wp-scripts format",
"format:src": "wp-scripts format ./src"
}
}
```
This is how you execute the script with presented setup:
- `npm run format` - formats files in the entire projects directories.
- `npm run format:src` - formats files in the projects `src` subfolders directories.
When you run commands similar to the `npm run format:src` example above, you can provide a file, a directory, or `glob` syntax or any combination of them.
By default, files located in `build`, `node_modules`, and `vendor` folders are ignored. You can customize the list of ignored files and directories by adding them to a `.prettierignore` file in your project.
### `lint-js`
Helps enforce coding style guidelines for your JavaScript and TypeScript files.
_Example:_
```json
{
"scripts": {
"lint:js": "wp-scripts lint-js",
"lint:js:src": "wp-scripts lint-js ./src"
}
}
```
This is how you execute the script with presented setup:
- `npm run lint:js` - lints JavaScript and TypeScript files in the entire projects directories.
- `npm run lint:js:src` - lints JavaScript and TypeScript files in the projects `src` subfolders directories.
When you run commands similar to the `npm run lint:js:src` example above, you can provide a file, a directory, or `glob` syntax or any combination of them. See [more examples](https://eslint.org/docs/user-guide/command-line-interface).
By default, files located in `build`, `node_modules`, and `vendor` folders are ignored.
#### Advanced information
It uses [eslint](https://eslint.org/) with the set of recommended rules defined in [@wordpress/eslint-plugin](https://www.npmjs.com/package/@wordpress/eslint-plugin) npm package. You can override default rules with your own as described in [eslint docs](https://eslint.org/docs/rules/). Learn more in the [Advanced Usage](#advanced-usage) section.
### `lint-pkg-json`
Helps enforce standards for your `package.json` files.
_Example:_
```json
{
"scripts": {
"lint:pkg-json": "wp-scripts lint-pkg-json",
"lint:pkg-json:src": "wp-scripts lint-pkg-json ./src"
}
}
```
This is how you execute those scripts using the presented setup:
- `npm run lint:pkg-json` - lints `package.json` file in the entire projects directories.
- `npm run lint:pkg-json:src` - lints `package.json` file in the projects `src` subfolders directories.
When you run commands similar to the `npm run lint:pkg-json:src` example above, you can provide one or multiple directories to scan as well. See [more examples](https://github.com/tclindner/npm-package-json-lint/blob/HEAD/README.md#examples).
By default, files located in `build`, `node_modules`, and `vendor` folders are ignored.
#### Advanced information
It uses [npm-package-json-lint](https://www.npmjs.com/package/npm-package-json-lint) with the set of recommended rules defined in [@wordpress/npm-package-json-lint-config](https://www.npmjs.com/package/@wordpress/npm-package-json-lint-config) npm package. You can override default rules with your own as described in [npm-package-json-lint wiki](https://github.com/tclindner/npm-package-json-lint/wiki). Learn more in the [Advanced Usage](#advanced-usage) section.
### `lint-md-docs`
Uses markdownlint to lint the markup of markdown files to enforce standards.
_Example:_
```json
{
"scripts": {
"lint:md:docs": "wp-scripts lint-md-docs"
}
}
```
This is how you execute the script with presented setup:
- `npm run lint:md:docs` - lints markdown files in the entire projects directories.
By default, files located in `build`, `node_modules`, and `vendor` folders are ignored.
#### Advanced information
It uses [markdownlint](https://github.com/DavidAnson/markdownlint) with the [.markdownlint.json](https://github.com/WordPress/gutenberg/blob/HEAD/packages/scripts/config/.markdownlint.json) configuration. This configuration tunes the linting rules to match WordPress standard, you can override with your own config, see [markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli/) for command-line parameters.
### `lint-style`
Helps enforce coding style guidelines for your style files.
_Example:_
```json
{
"scripts": {
"lint:style": "wp-scripts lint-style",
"lint:css:src": "wp-scripts lint-style 'src/**/*.css'"
}
}
```
This is how you execute the script with presented setup:
- `npm run lint:style` - lints CSS, PCSS, and SCSS files in the entire projects directories.
- `npm run lint:css:src` - lints only CSS files in the projects `src` subfolders directories.
When you run commands similar to the `npm run lint:css:src` example above, be sure to include the quotation marks around file globs. This ensures that you can use the powers of [globby](https://github.com/sindresorhus/globby) (like the `**` globstar) regardless of your shell. See [more examples](https://github.com/stylelint/stylelint/blob/HEAD/docs/user-guide/cli.md#examples).
By default, files located in `build`, `node_modules`, and `vendor` folders are ignored.
#### Advanced information
It uses [stylelint](https://github.com/stylelint/stylelint) with the [@wordpress/stylelint-config](https://www.npmjs.com/package/@wordpress/stylelint-config) configuration per the [WordPress CSS Coding Standards](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/css/). You can override them with your own rules as described in [stylelint user guide](https://stylelint.io/user-guide/configure). Learn more in the [Advanced Usage](#advanced-usage) section.
### `packages-update`
Updates the WordPress packages used in the project to their latest version.
_Example:_
```json
{
"scripts": {
"packages-update": "wp-scripts packages-update",
"postpackages-update": "npm run build"
}
}
```
This script provides the following custom options:
- `--dist-tag` allows specifying a custom dist-tag when updating npm packages. Defaults to `latest`. This is especially useful when using [`@wordpress/dependency-extraction-webpack-plugin`](https://www.npmjs.com/package/@wordpress/dependency-extraction-webpack-plugin). It lets installing the npm dependencies at versions used by the given WordPress major version for local testing, etc. Example: `wp-scripts packages-update --dist-tag=wp-6.0`.
#### Advanced information
The command detects project dependencies that have name starting with `@wordpress/` by scanning the `package.json` file. By default, it executes `npm install @wordpress/package1@latest @wordpress/package2@latest ... --save` to change the package versions to the latest one. You can chose a different dist-tag than `latest` by using the `--dist-tag` option when running the command.
### `plugin-zip`
Creates a zip file for a WordPress plugin.
_Example:_
```json
{
"scripts": {
"plugin-zip": "wp-scripts plugin-zip"
}
}
```
By default, it uses [Plugin Handbook best practices](https://developer.wordpress.org/plugins/plugin-basics/best-practices/#file-organization) to discover files.
#### Advanced information
In the case where the plugin author wants to customize the files included in the zip file, they can provide the `files` field in the `package.json` file as documented in the [`npm-packlist`](https://www.npmjs.com/package/npm-packlist) package, example:
```json
{
"files": [ "dir" ]
}
```
It reuses the same logic as `npm pack` command to create an npm package tarball.
### `start`
Transforms your code according the configuration provided so its ready for development. The script will automatically rebuild if you make changes to the code, and you will see the build errors in the console.
_For single builds, better suited for production, see the [build](#build) script._
The entry points for your project get detected by scanning all script fields in `block.json` files located in the `src` directory. The script fields in `block.json` should pass relative paths to `block.json` in the same folder.
_Example:_
```json
{
"editorScript": "file:index.js",
"script": "file:script.js",
"viewScript": "file:view.js"
}
```
The fallback entry point is `src/index.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) in case there is no `block.json` file found. In that scenario, the output generated will be written to `build/index.js`.
_Example:_
```json
{
"scripts": {
"start": "wp-scripts start",
"start:hot": "wp-scripts start --hot",
"start:custom": "wp-scripts start entry-one.js entry-two.js --output-path=custom",
"start:copy-php": "wp-scripts start --webpack-copy-php",
"start:custom-directory": "wp-scripts start --webpack-src-dir=custom-directory"
}
}
```
This is how you execute the script with presented setup:
- `npm start` - starts the build for development.
- `npm run start:hot` - starts the build for development with "Fast Refresh". The page will automatically reload if you make changes to the files.
- `npm run start:custom` - starts the build for development which contains two entry points and a custom output directory. Paths for custom entry points are relative to the project root.
- `npm run start:copy-php` - starts the build for development and opts into copying all PHP files from the `src` directory and its subfolders to the output directory. By default, only PHP files listed in the `render` field in the detected `block.json` files get copied.
- `npm run start:custom-directory` - builds the code for production using the `custom-directory` as the source code directory.
This script automatically use the optimized config but sometimes you may want to specify some custom options:
- `--hot` enables "Fast Refresh". The page will automatically reload if you make changes to the code. _For now, it requires that WordPress has the [`SCRIPT_DEBUG`](https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/#script_debug) flag enabled and the [Gutenberg](https://wordpress.org/plugins/gutenberg/) plugin installed._
- `--no-watch` Starts the build for development without starting the watcher.
- `--webpack-bundle-analyzer` enables visualization for the size of webpack output files with an interactive zoomable treemap.
- `--webpack-copy-php` enables copying all PHP files from the source directory ( default is `src` ) and its subfolders to the output directory.
- `--webpack-devtool` controls how source maps are generated. See options at https://webpack.js.org/configuration/devtool/#devtool.
- `--webpack-no-externals` disables scripts' assets generation, and omits the list of default externals.
- `--webpack-src-dir` Allows customization of the source code directory. Default is `src`.
- `--output-path` Allows customization of the output directory. Default is `build`.
Experimental support for the block.json `viewScriptModule` field is available via the
`--experimental-modules` option. With this option enabled, script and module fields will all be
compiled. The `viewScriptModule` field is analogous to the `viewScript` field, but will compile a module
and should be registered in WordPress using the Modules API.
#### Advanced information
This script uses [webpack](https://webpack.js.org/) behind the scenes. Itll look for a webpack config in the top-level directory of your package and will use it if it finds one. If none is found, itll use the default config provided by `@wordpress/scripts` packages. Learn more in the [Advanced Usage](#advanced-usage) section.
### `test-e2e`
Launches the End-To-End (E2E) test runner. Writing tests can be done using the [Jest API](https://jestjs.io/docs/en/api) in combination with the [Puppeteer API](https://github.com/GoogleChrome/puppeteer/blob/HEAD/docs/api.md):
> [Jest](https://jestjs.io/) is a delightful JavaScript Testing Framework with a focus on simplicity.
> [Puppeteer](https://pptr.dev/) is a Node library which provides a high-level API to control Chrome or Chromium over the [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). Puppeteer runs [headless](https://developers.google.com/web/updates/2017/04/headless-chrome) by default, but can be configured to run full (non-headless) Chrome or Chromium.
_Example:_
```json
{
"scripts": {
"test:e2e": "wp-scripts test-e2e",
"test:e2e:help": "wp-scripts test-e2e --help",
"test:e2e:debug": "wp-scripts --inspect-brk test-e2e --puppeteer-devtools"
}
}
```
This is how you execute those scripts using the presented setup:
- `npm run test:e2e` - runs all e2e tests.
- `npm run test:e2e:help` - prints all available options to configure e2e test runner.
- `npm run test:e2e -- --puppeteer-interactive` - runs all e2e tests interactively.
- `npm run test:e2e FILE_NAME -- --puppeteer-interactive` - runs one test file interactively.
- `npm run test:e2e:watch -- --puppeteer-interactive` - runs all tests interactively and watch for changes.
- `npm run test:e2e:debug` - runs all tests interactively and enables [debugging tests](#debugging-e2e-tests).
Jest will look for test files with any of the following popular naming conventions:
- Files with `.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) suffix at any level of depth in `spec` folders.
- Files with `.spec.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) suffix.
This script automatically detects the best config to start Puppeteer but sometimes you may need to specify custom options:
- You can add a `jest-puppeteer.config.js` at the root of the project or define a custom path using `JEST_PUPPETEER_CONFIG` environment variable. Check [jest-puppeteer](https://github.com/smooth-code/jest-puppeteer#jest-puppeteerconfigjs) for more details.
We enforce that all tests run serially in the current process using [--runInBand](https://jestjs.io/docs/en/cli#runinband) Jest CLI option to avoid conflicts between tests caused by the fact that they share the same WordPress instance.
#### Failed Test Artifacts
When tests fail, both a screenshot and an HTML snapshot will be taken of the page and stored in the `artifacts/` directory at the root of your project. These snapshots may help debug failed tests during development or when running tests in a CI environment.
The `artifacts/` directory can be customized by setting the `WP_ARTIFACTS_PATH` environment variable to the relative path of the desired directory within your project's root. For example: to change the default directory from `artifacts/` to `my/custom/artifacts`, you could use `WP_ARTIFACTS_PATH=my/custom/artifacts npm run test:e2e`.
#### Advanced information
It uses [Jest](https://jestjs.io/) behind the scenes and you are able to use all of its [CLI options](https://jestjs.io/docs/en/cli.html). You can also run `./node_modules/.bin/wp-scripts test:e2e --help` or `npm run test:e2e:help` (as mentioned above) to view all of the available options. Learn more in the [Advanced Usage](#advanced-usage) section.
Should there be any situation where you want to provide your own Jest config, you can do so.
- the command receives a `--config` argument. Example: `wp-scripts test-e2e --config my-jest-config.js`.
- there is a file called `jest-e2e.config.js`, `jest-e2e.config.json`, `jest.config.js`, or `jest.config.json` in the top-level directory of your package (at the same level than your `package.json`).
- a `jest` object can be provided in the `package.json` file with the test configuration.
### `test-unit-js`
_Alias_: `test-unit-jest`
Launches the unit test runner. Writing tests can be done using the [Jest API](https://jestjs.io/docs/en/api).
_Example:_
```json
{
"scripts": {
"test:unit": "wp-scripts test-unit-js",
"test:unit:help": "wp-scripts test-unit-js --help",
"test:unit:watch": "wp-scripts test-unit-js --watch",
"test:unit:debug": "wp-scripts --inspect-brk test-unit-js --runInBand --no-cache"
}
}
```
This is how you execute those scripts using the presented setup:
- `npm run test:unit` - runs all unit tests.
- `npm run test:unit:help` - prints all available options to configure unit tests runner.
- `npm run test:unit:watch` - runs all unit tests in the watch mode.
- `npm run test:unit:debug` - runs all unit tests in [debug mode](#debugging-tests).
Jest will look for test files with any of the following popular naming conventions:
- Files with `.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) suffix located at any level of depth in `__tests__` folders.
- Files with `.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) suffix directly located in `test` folders.
- Files with `.test.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) suffix.
#### Advanced information
It uses [Jest](https://jestjs.io/) behind the scenes and you are able to use all of its [CLI options](https://jestjs.io/docs/en/cli.html). You can also run `./node_modules/.bin/wp-scripts test:unit --help` or `npm run test:unit:help` (as mentioned above) to view all of the available options. By default, it uses the set of recommended options defined in [@wordpress/jest-preset-default](https://www.npmjs.com/package/@wordpress/jest-preset-default) npm package. You can override them with your own options as described in [Jest documentation](https://jestjs.io/docs/en/configuration). Learn more in the [Advanced Usage](#advanced-usage) section.
Should there be any situation where you want to provide your own Jest config, you can do so.
- the command receives a `--config` argument. Example: `wp-scripts test-unit --config my-jest-config.js`.
- there is a file called `jest-unit.config.js`, `jest-unit.config.json`, `jest.config.js`, or `jest.config.json` in the top-level directory of your package (at the same level than your `package.json`).
- a `jest` object can be provided in the `package.json` file with the test configuration.
### `test-playwright`
Launches the Playwright End-To-End (E2E) test runner. Similar to Puppeteer, it provides a high-level API to control a headless browser.
Refer to the [Getting Started guide](https://playwright.dev/docs/writing-tests) to learn how to write tests.
_Example:_
```json
{
"scripts": {
"test:playwright": "wp-scripts test-playwright",
"test:playwright:help": "wp-scripts test-playwright --help",
"test:playwright:debug": "wp-scripts test-playwright --debug"
}
}
```
This is how you execute those scripts using the presented setup:
- `npm run test:playwright` - runs all tests.
- `npm run test:playwright:help` - prints all available options to configure the test runner.
- `npm run test:playwright:debug` - runs all tests interactively with the Playwright inspector.
- `npm run test:playwright FILE_NAME` - runs a specific test file.
- `npm run test:playwright -- --watch` - runs all tests interactively with watch mode and enhanced debugging.
By default, Playwright looks for JavaScript or TypeScript files with `.test` or `.spec` suffix in the project root-level `/specs` folder, for example `/specs/login-screen.wrong-credentials.spec.ts`.
This script automatically detects the best config to start Playwright, but sometimes you may need to specify custom options.
To do so, you can add a file called `playwright.config.ts` or `playwright.config.js` in the top-level directory of your package (at the same level as your `package.json`).
#### Failed Test Artifacts
When tests fail, snapshots will be taken of the page and stored in the `artifacts/` directory at the root of your project. These snapshots may help debug failed tests during development or when running tests in a CI environment.
The `artifacts/` directory can be customized by setting the `WP_ARTIFACTS_PATH` environment variable to the relative path of the desired directory within your project's root. For example: to change the default directory from `artifacts/` to `my/custom/artifacts`, you could use `WP_ARTIFACTS_PATH=my/custom/artifacts npm run test:playwright`.
#### Advanced information
You are able to use all of Playwright's [CLI options](https://playwright.dev/docs/test-cli#reference). You can also run `./node_modules/.bin/wp-scripts test-playwright --help` or `npm run test:playwright:help` (as mentioned above) to view all the available options. Learn more in the [Advanced Usage](#advanced-usage) section.
## Passing Node.js options
`wp-scripts` supports the full array of [Node.js CLI options](https://nodejs.org/api/cli.html). They can be passed after the `wp-scripts` command and before the script name.
```sh
wp-scripts [NODE_OPTIONS] script
```
### Debugging tests
One common use-case for passing Node.js options is debugging your tests.
Tests can be debugged by any [inspector client](https://nodejs.org/en/docs/guides/debugging-getting-started/#inspector-clients) that supports the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/).
Follow the instructions for debugging Node.js with your favorite supported browser or IDE. When the instructions say to use `node --inspect script.js` or `node --inspect-brk script.js`, simply use `wp-scripts --inspect script` or `wp-scripts --inspect-brk script` instead.
Google Chrome and Visual Studio Code are used as examples below.
#### Debugging in Google Chrome
Place `debugger;` statements in any test and run `wp-scripts --inspect-brk test-unit-js --runInBand --no-cache` (or `npm run test:unit:debug` from above).
Then open `about:inspect` in Google Chrome and select `inspect` on your process.
A breakpoint will be set at the first line of the script (this is done to give you time to open the developer tools and to prevent Jest from executing before you have time to do so). Click the resume button in the upper right panel of the dev tools to continue execution. When Jest executes the test that contains the debugger statement, execution will pause and you can examine the current scope and call stack.
#### Debugging in Visual Studio Code
Debugging npm scripts is supported out of the box for Visual Studio Code as of [version 1.23](https://code.visualstudio.com/blogs/2018/07/12/introducing-logpoints-and-auto-attach#_npm-scripts-and-debugging) and can be used to debug Jest unit tests.
Make sure `wp-scripts --inspect-brk test-unit-js --runInBand --no-cache` is saved as `test:unit:debug` in your `package.json` file to run tests in Visual Studio Code.
When debugging, set a breakpoint in your tests by clicking on a line in the editors left margin by the line numbers.
Then open npm scripts in the explorer or run `Explorer: Focus on NPM Scripts View` in the command palette to see the npm scripts. To start the tests, click the debug icon next to `test:unit:debug`.
The tests will start running, and execution will pause on your selected line so you can inspect the current scope and call stack within the editor.
See [Debugging in Visual Studio Code](https://code.visualstudio.com/Docs/editor/debugging) for more details on using the Visual Studio Code debugger.
#### Debugging e2e tests
Since e2e tests run both in the node context _and_ the (usually headless) browser context, not all lines of code can have breakpoints set within the inspector client—only the node context is debugged in the inspector client.
The code executed in the node context includes all of the test files _excluding_ code within `page.evaluate` functions. The `page.evaluate` functions and the rest of your app code is executed within the browser context.
Test code (node context) can be debugged normally using the instructions above.
To also debug the browser context, run `wp-scripts --inspect-brk test-e2e --puppeteer-devtools`. The `--puppeteer-devtools` option (or the `PUPPETEER_DEVTOOLS="true"` environment variable when used with `PUPPETEER_HEADLESS="false"`) will disable headless mode and launch the browser with the devtools already open. Breakpoints can then be set in the browser context using these devtools.
For more e2e debugging tips check out the [Puppeteer debugging docs](https://developers.google.com/web/tools/puppeteer/debugging).
## Advanced Usage
In general, this package should be used with the set of recommended config files. While its possible to override every single config file provided, if you have to do it, it means that your use case is far more complicated than anticipated. If that happens, it would be better to avoid using the whole abstraction layer and set up your project with full control over tooling used.
### Working with build scripts
The `build` and `start` commands use [webpack](https://webpack.js.org/) behind the scenes. webpack is a tool that helps you transform your code into something else. For example: it can take code written in ESNext and output ES5 compatible code that is minified for production.
#### Default webpack config
`@wordpress/scripts` bundles the default webpack config used as a base by the WordPress editor. These are the defaults:
- [Entry](https://webpack.js.org/configuration/entry-context/#entry): the entry points for your project get detected by scanning all script fields in `block.json` files located in the `src` directory. The fallback entry point is `src/index.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) in case there is no `block.json` file found.
- [Output](https://webpack.js.org/configuration/output): `build/[name].js`, for example: `build/index.js`, or `build/my-block/index.js`.
- [Loaders](https://webpack.js.org/loaders/):
- [`babel-loader`](https://webpack.js.org/loaders/babel-loader/) allows transpiling JavaScript and TypeScript files using Babel and webpack.
- [`@svgr/webpack`](https://www.npmjs.com/package/@svgr/webpack) and [`url-loader`](https://webpack.js.org/loaders/url-loader/) makes it possible to handle SVG files in JavaScript code.
- [`css-loader`](https://webpack.js.org/loaders/css-loader/) chained with [`postcss-loader`](https://webpack.js.org/loaders/postcss-loader/) and [sass-loader](https://webpack.js.org/loaders/sass-loader/) let webpack process CSS, SASS or SCSS files referenced in JavaScript files.
- [Plugins](https://webpack.js.org/configuration/plugins) (among others):
- [`CopyWebpackPlugin`](https://webpack.js.org/plugins/copy-webpack-plugin/) copies all `block.json` files discovered in the `src` directory to the build directory.
- [`MiniCssExtractPlugin`](https://webpack.js.org/plugins/mini-css-extract-plugin/) extracts CSS into separate files. It creates a CSS file per JavaScript entry point which contains CSS.
- [`@wordpress/dependency-extraction-webpack-plugin`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/dependency-extraction-webpack-plugin/README.md) is used with the default configuration to ensure that WordPress provided scripts are not included in the built bundle.
#### Using CSS
_Example:_
```scss
// index.scss
$body-color: red;
.wp-block-my-block {
color: $body-color;
}
```
```css
/* style.css */
.wp-block-my-block {
background-color: black;
}
```
```js
// index.js
import './index.pcss';
import './index.scss';
import './style.css';
```
When you run the build using the default command `wp-scripts build` (also applies to `start`) in addition to the JavaScript file `index.js` generated in the `build` folder, you should see two more files:
1. `index.css` all imported CSS files are bundled into one chunk named after the entry point, which defaults to `index.js`, and thus the file created becomes `index.css`. This is for styles used only in the editor.
2. `style-index.css` imported `style.css` file(s) (applies to PCSS, SASS and SCSS extensions) get bundled into one `style-index.css` file that is meant to be used both on the front-end and in the editor.
You can also have multiple entry points as described in the docs for the script:
```bash
wp-scripts start entry-one.js entry-two.js --output-path=custom
```
If you do so, then CSS files generated will follow the names of the entry points: `entry-one.css` and `entry-two.css`.
Avoid using `style` keyword in an entry point name, this might break your build process.
You can also bundle CSS modules by prefixing `.module` to the extension, e.g. `style.module.scss`. Otherwise, these files are handled like all other `style.scss`. They will also be extracted into `style-index.css`.
#### Using fonts and images
It is possible to reference font (`woff`, `woff2`, `eot`, `ttf` and `otf`) and image (`bmp`, `png`, `jpg`, `jpeg`, `gif` and `wepb`) files from CSS that is controlled by webpack as explained in the previous section.
_Example:_
```css
/* style.css */
@font-face {
font-family: Gilbert;
src: url( ../assets/gilbert-color.otf );
}
.wp-block-my-block {
background-color: url( ../assets/block-background.png );
font-family: Gilbert;
}
```
#### Using SVG
_Example:_
```js
import starUrl, { ReactComponent as Star } from './star.svg';
const App = () => (
<div>
<img src={ starUrl } alt="star" />
<Star />
</div>
);
```
#### Provide your own webpack config
Should there be any situation where you want to provide your own webpack config, you can do so. The `build` and `start` commands will use your provided file when:
- the command receives a `--config` argument. Example: `wp-scripts build --config my-own-webpack-config.js`.
- there is a file called `webpack.config.js` or `webpack.config.babel.js` in the top-level directory of your project (at the same level as `package.json`).
##### Extending the webpack config
To extend the provided webpack config, or replace subsections within the provided webpack config, you can provide your own `webpack.config.js` file, `require` the provided `webpack.config.js` file, and use the [`spread` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) to import all of or part of the provided configuration.
In the example below, a `webpack.config.js` file is added to the root folder extending the provided webpack config to include custom logic to parse module's source and convert it to a JavaScript object using [`toml`](https://www.npmjs.com/package/toml). It may be useful to import toml or other non-JSON files as JSON, without specific loaders:
```javascript
const toml = require( 'toml' );
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
module.exports = {
...defaultConfig,
module: {
...defaultConfig.module,
rules: [
...defaultConfig.module.rules,
{
test: /.toml/,
type: 'json',
parser: {
parse: toml.parse,
},
},
],
},
};
```
If you follow this approach, please, be aware that:
- You should keep using the `wp-scripts` commands (`start` and `build`). Do not use `webpack` directly.
- Future versions of this package may change what webpack and Babel plugins we bundle, default configs, etc. Should those changes be necessary, they will be registered in the [packages CHANGELOG](https://github.com/WordPress/gutenberg/blob/HEAD/packages/scripts/CHANGELOG.md), so make sure to read it before upgrading.
## Contributing to this package
This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects.
To find out more about contributing to this package or Gutenberg as a whole, please read the project's main [contributor guide](https://github.com/WordPress/gutenberg/tree/HEAD/CONTRIBUTING.md).
<br /><br /><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>

10
node_modules/@wordpress/scripts/bin/wp-scripts.js generated vendored Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env node
/**
* Internal dependencies
*/
const { getNodeArgsFromCLI, spawnScript } = require( '../utils' );
const { scriptName, scriptArgs, nodeArgs } = getNodeArgsFromCLI();
spawnScript( scriptName, scriptArgs, nodeArgs );

View File

@@ -0,0 +1 @@
extends @wordpress/browserslist-config

3
node_modules/@wordpress/scripts/config/.eslintignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
build
node_modules
vendor

27
node_modules/@wordpress/scripts/config/.eslintrc.js generated vendored Normal file
View File

@@ -0,0 +1,27 @@
/**
* Internal dependencies
*/
const { hasBabelConfig } = require( '../utils' );
const eslintConfig = {
root: true,
extends: [ 'plugin:@wordpress/eslint-plugin/recommended' ],
overrides: [
{
// Unit test files and their helpers only.
files: [ '**/@(test|__tests__)/**/*.js', '**/?(*.)test.js' ],
extends: [ 'plugin:@wordpress/eslint-plugin/test-unit' ],
},
],
};
if ( ! hasBabelConfig() ) {
eslintConfig.parserOptions = {
requireConfigFile: false,
babelOptions: {
presets: [ require.resolve( '@wordpress/babel-preset-default' ) ],
},
};
}
module.exports = eslintConfig;

View File

@@ -0,0 +1,8 @@
{
"default": true,
"MD003": { "style": "atx" },
"MD007": { "indent": 4 },
"MD013": { "line_length": 9999 },
"no-hard-tabs": false,
"whitespace": false
}

View File

@@ -0,0 +1,3 @@
**/build/**
**/node_modules/**
**/vendor/**

View File

@@ -0,0 +1,5 @@
# By default, all `node_modules` are ignored.
build
vendor
wordpress

View File

@@ -0,0 +1,2 @@
build
vendor

View File

@@ -0,0 +1 @@
module.exports = require( '@wordpress/prettier-config' );

View File

@@ -0,0 +1,4 @@
# By default, all `node_modules` are ignored.
build
vendor

View File

@@ -0,0 +1,6 @@
{
"extends": "@wordpress/stylelint-config/scss",
"rules": {
"selector-class-pattern": null
}
}

View File

@@ -0,0 +1,11 @@
/**
* External dependencies
*/
const babelJest = require( 'babel-jest' );
// Remove this workaround when https://github.com/facebook/jest/issues/11444 gets resolved in Jest.
const babelJestInterop = babelJest.__esModule ? babelJest.default : babelJest;
module.exports = babelJestInterop.createTransformer( {
presets: [ '@wordpress/babel-preset-default' ],
} );

View File

@@ -0,0 +1,13 @@
services:
wordpress-develop:
volumes:
- %PLUGIN_MOUNT_DIR%:/var/www/${LOCAL_DIR-src}/wp-content/plugins/%PLUGIN_INSTALL_DIR%
php:
volumes:
- %PLUGIN_MOUNT_DIR%:/var/www/${LOCAL_DIR-src}/wp-content/plugins/%PLUGIN_INSTALL_DIR%
cli:
volumes:
- %PLUGIN_MOUNT_DIR%:/var/www/${LOCAL_DIR-src}/wp-content/plugins/%PLUGIN_INSTALL_DIR%
phpunit:
volumes:
- %PLUGIN_MOUNT_DIR%:/var/www/${LOCAL_DIR-src}/wp-content/plugins/%PLUGIN_INSTALL_DIR%

View File

@@ -0,0 +1,36 @@
/**
* External dependencies
*/
const path = require( 'path' );
/**
* Internal dependencies
*/
const { hasBabelConfig } = require( '../utils' );
const jestE2EConfig = {
globalSetup: path.join( __dirname, 'jest-environment-puppeteer', 'setup' ),
globalTeardown: path.join(
__dirname,
'jest-environment-puppeteer',
'teardown'
),
reporters: [
'default',
path.join( __dirname, 'jest-github-actions-reporter', 'index.js' ),
],
setupFilesAfterEnv: [ 'expect-puppeteer' ],
testEnvironment: path.join( __dirname, 'jest-environment-puppeteer' ),
testMatch: [ '**/specs/**/*.[jt]s?(x)', '**/?(*.)spec.[jt]s?(x)' ],
testPathIgnorePatterns: [ '/node_modules/' ],
testRunner: 'jest-circus/runner',
testTimeout: 30000,
};
if ( ! hasBabelConfig() ) {
jestE2EConfig.transform = {
'\\.[jt]sx?$': path.join( __dirname, 'babel-transform' ),
};
}
module.exports = jestE2EConfig;

View File

@@ -0,0 +1,85 @@
/**
* Parts of this source were derived and modified from the package
* jest-environment-puppeteer, released under the MIT license.
*
* https://github.com/smooth-code/jest-puppeteer/tree/master/packages/jest-environment-puppeteer
*
* Copyright 2018 Smooth Code
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* External dependencies
*/
const fs = require( 'fs' );
const path = require( 'path' );
const { promisify } = require( 'util' );
const cwd = require( 'cwd' );
const merge = require( 'merge-deep' );
const exists = promisify( fs.exists );
const DEFAULT_CONFIG = {
launch: {},
browser: 'chromium',
browserContext: 'default',
exitOnPageError: true,
};
const DEFAULT_CONFIG_CI = merge( DEFAULT_CONFIG, {
launch: {
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
],
},
} );
async function readConfig() {
const defaultConfig =
process.env.CI === 'true' ? DEFAULT_CONFIG_CI : DEFAULT_CONFIG;
const hasCustomConfigPath = !! process.env.JEST_PUPPETEER_CONFIG;
const configPath =
process.env.JEST_PUPPETEER_CONFIG || 'jest-puppeteer.config.js';
const absConfigPath = path.resolve( cwd(), configPath );
const configExists = await exists( absConfigPath );
if ( hasCustomConfigPath && ! configExists ) {
throw new Error(
`Error: Can't find a root directory while resolving a config file path.\nProvided path to resolve: ${ configPath }`
);
}
if ( ! hasCustomConfigPath && ! configExists ) {
return defaultConfig;
}
const localConfig = await require( absConfigPath );
return merge( {}, defaultConfig, localConfig );
}
function getPuppeteer( { browser } ) {
switch ( browser.toLowerCase() ) {
case 'chromium':
return require( 'puppeteer-core' );
case 'firefox':
return require( 'puppeteer-firefox' );
default:
throw new Error(
`Error: "browser" config option is given an unsupported value: ${ browser }`
);
}
}
module.exports = {
readConfig,
getPuppeteer,
};

View File

@@ -0,0 +1,101 @@
/**
* Parts of this source were derived and modified from the package
* jest-environment-puppeteer, released under the MIT license.
*
* https://github.com/smooth-code/jest-puppeteer/tree/master/packages/jest-environment-puppeteer
*
* Copyright 2018 Smooth Code
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* External dependencies
*/
const {
setup: setupServer,
teardown: teardownServer,
ERROR_TIMEOUT,
ERROR_NO_COMMAND,
} = require( 'jest-dev-server' );
const chalk = require( 'chalk' );
/**
* Internal dependencies
*/
const { readConfig, getPuppeteer } = require( './config' );
let browser;
let didAlreadyRunInWatchMode = false;
let servers = [];
async function setup( jestConfig = {} ) {
const config = await readConfig();
const puppeteer = getPuppeteer( config );
if ( config.connect ) {
browser = await puppeteer.connect( config.connect );
} else {
browser = await puppeteer.launch( config.launch );
}
process.env.PUPPETEER_WS_ENDPOINT = browser.wsEndpoint();
// If we are in watch mode, - only setupServer() once.
if ( jestConfig.watch || jestConfig.watchAll ) {
if ( didAlreadyRunInWatchMode ) {
return;
}
didAlreadyRunInWatchMode = true;
}
if ( config.server ) {
try {
servers = await setupServer( config.server );
} catch ( error ) {
const { error: printError } = console;
if ( error.code === ERROR_TIMEOUT ) {
printError( '' );
printError( chalk.red( error.message ) );
printError(
chalk.blue(
`\n☝️ You can set "server.launchTimeout" in jest-puppeteer.config.js`
)
);
process.exit( 1 );
}
if ( error.code === ERROR_NO_COMMAND ) {
printError( '' );
printError( chalk.red( error.message ) );
printError(
chalk.blue(
`\n☝️ You must set "server.command" in jest-puppeteer.config.js`
)
);
process.exit( 1 );
}
throw error;
}
}
}
async function teardown( jestConfig = {} ) {
const config = await readConfig();
if ( config.connect ) {
await browser.disconnect();
} else {
await browser.close();
}
if ( ! jestConfig.watch && ! jestConfig.watchAll ) {
await teardownServer( servers );
}
}
module.exports = {
setup,
teardown,
};

View File

@@ -0,0 +1,221 @@
/**
* Parts of this source were derived and modified from the package
* jest-environment-puppeteer, released under the MIT license.
*
* https://github.com/smooth-code/jest-puppeteer/tree/master/packages/jest-environment-puppeteer
*
* Copyright 2018 Smooth Code
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* External dependencies
*/
const path = require( 'path' );
const { writeFile, mkdir } = require( 'fs' ).promises;
const filenamify = require( 'filenamify' );
const NodeEnvironment = require( 'jest-environment-node' ).default;
const chalk = require( 'chalk' );
/**
* Internal dependencies
*/
const { readConfig, getPuppeteer } = require( './config' );
const handleError = ( error ) => {
// To match the same behavior in jest-jasmine2:
// https://github.com/facebook/jest/blob/1be8d737abd0e2f30e3314184a0efc372ad6d88f/packages/jest-jasmine2/src/jasmine/Env.ts#L250-L251
// Emitting an uncaughtException event to the process will throw an
// empty error which is very hard to debug in puppeteer context.
// eslint-disable-next-line no-console
console.error( error );
};
const KEYS = {
CONTROL_C: '\u0003',
CONTROL_D: '\u0004',
ENTER: '\r',
};
const { WP_ARTIFACTS_PATH } = process.env;
class PuppeteerEnvironment extends NodeEnvironment {
// Jest is not available here, so we have to reverse engineer
// the setTimeout function, see https://github.com/facebook/jest/blob/v23.1.0/packages/jest-runtime/src/index.js#L823
setTimeout( timeout ) {
this.global[ Symbol.for( 'TEST_TIMEOUT_SYMBOL' ) ] = timeout;
}
async setup() {
const config = await readConfig();
const puppeteer = getPuppeteer( config );
this.global.puppeteerConfig = config;
const wsEndpoint = process.env.PUPPETEER_WS_ENDPOINT;
if ( ! wsEndpoint ) {
throw new Error( 'wsEndpoint not found' );
}
this.global.jestPuppeteer = {
debug: async () => {
// Set timeout to 4 days.
this.setTimeout( 345600000 );
// Run a debugger (in case Puppeteer has been launched with `{ devtools: true }`)
await this.global.page.evaluate( () => {
// eslint-disable-next-line no-debugger
debugger;
} );
// eslint-disable-next-line no-console
console.log(
chalk.blue(
'\n\n🕵 Code is paused, press enter to resume'
)
);
// Run an infinite promise.
return new Promise( ( resolve ) => {
const { stdin } = process;
const onKeyPress = ( key ) => {
if (
key === KEYS.CONTROL_C ||
key === KEYS.CONTROL_D ||
key === KEYS.ENTER
) {
stdin.removeListener( 'data', onKeyPress );
if ( ! listening ) {
if ( stdin.isTTY ) {
stdin.setRawMode( false );
}
stdin.pause();
}
resolve();
}
};
const listening = stdin.listenerCount( 'data' ) > 0;
if ( ! listening ) {
if ( stdin.isTTY ) {
stdin.setRawMode( true );
}
stdin.resume();
stdin.setEncoding( 'utf8' );
}
stdin.on( 'data', onKeyPress );
} );
},
resetPage: async () => {
if ( this.global.page ) {
this.global.page.removeListener( 'pageerror', handleError );
await this.global.page.close();
}
this.global.page = await this.global.context.newPage();
if ( config && config.exitOnPageError ) {
this.global.page.addListener( 'pageerror', handleError );
}
},
resetBrowser: async () => {
if ( this.global.page ) {
this.global.page.removeListener( 'pageerror', handleError );
}
if (
config.browserContext === 'incognito' &&
this.global.context
) {
await this.global.context.close();
} else if ( this.global.page ) {
await this.global.page.close();
}
this.global.page = null;
if ( this.global.browser ) {
await this.global.browser.disconnect();
}
this.global.browser = await puppeteer.connect( {
...config.connect,
...config.launch,
browserURL: undefined,
browserWSEndpoint: wsEndpoint,
} );
if ( config.browserContext === 'incognito' ) {
// Using this, pages will be created in a pristine context.
this.global.context =
await this.global.browser.createIncognitoBrowserContext();
} else if (
config.browserContext === 'default' ||
! config.browserContext
) {
/**
* Since this is a new browser, browserContexts() will return only one instance
* https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#browserbrowsercontexts
*/
this.global.context =
await this.global.browser.browserContexts()[ 0 ];
} else {
throw new Error(
`browserContext should be either 'incognito' or 'default'. Received '${ config.browserContext }'`
);
}
await this.global.jestPuppeteer.resetPage();
},
};
await this.global.jestPuppeteer.resetBrowser();
try {
await mkdir( WP_ARTIFACTS_PATH, { recursive: true } );
} catch ( err ) {
if ( err.code !== 'EEXIST' ) {
throw err;
}
}
}
async teardown() {
const { page, context, browser, puppeteerConfig } = this.global;
if ( page ) {
page.removeListener( 'pageerror', handleError );
}
if ( puppeteerConfig.browserContext === 'incognito' ) {
if ( context ) {
await context.close();
}
} else if ( page ) {
await page.close();
}
if ( browser ) {
await browser.disconnect();
}
}
async storeArtifacts( testName ) {
const datetime = new Date().toISOString().split( '.' )[ 0 ];
const fileName = filenamify( `${ testName } ${ datetime }`, {
replacement: '-',
} );
await writeFile(
path.join( WP_ARTIFACTS_PATH, `${ fileName }-snapshot.html` ),
await this.global.page.content()
);
await this.global.page.screenshot( {
path: path.join( WP_ARTIFACTS_PATH, `${ fileName }.jpg` ),
} );
}
async handleTestEvent( event, state ) {
if ( event.name === 'test_fn_failure' ) {
const testName = state.currentlyRunningTest.name;
await this.storeArtifacts( testName );
}
}
}
module.exports = PuppeteerEnvironment;

View File

@@ -0,0 +1 @@
module.exports = require( './global' ).setup;

View File

@@ -0,0 +1 @@
module.exports = require( './global' ).teardown;

View File

@@ -0,0 +1,66 @@
/**
* Based on https://github.com/facebook/jest/pull/11320.
*
* We might be able to remove this file once the Jest PR is merged, and a
* version of Jest that includes the GithubActionsReporter is released.
*/
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const newLine = /\n/g;
const encodedNewLine = '%0A';
const lineAndColumnInStackTrace = /^.*?:([0-9]+):([0-9]+).*$/;
class GithubActionsReporter {
async onRunComplete( _contexts, _aggregatedResults ) {
if ( ! process.env.GITHUB_ACTIONS ) {
return;
}
if ( ! _aggregatedResults ) {
return;
}
const messages = getMessages( _aggregatedResults.testResults );
for ( const message of messages ) {
// eslint-disable-next-line no-console
console.log( message );
}
}
}
function getMessages( results ) {
if ( ! results ) {
return [];
}
return results.reduce(
flatMap( ( { testFilePath, testResults } ) =>
testResults
.filter( ( r ) => r.status === 'failed' )
.reduce(
flatMap( ( r ) => r.failureMessages ),
[]
)
.map( ( m ) => m.replace( newLine, encodedNewLine ) )
.map( ( m ) => lineAndColumnInStackTrace.exec( m ) )
.filter( ( m ) => m !== null )
.map(
( [ message, line, col ] ) =>
`::error file=${ testFilePath },line=${ line },col=${ col }::${ message }`
)
),
[]
);
}
function flatMap( fn ) {
return ( out, entry ) => out.concat( ...fn( entry ) );
}
module.exports = GithubActionsReporter;

View File

@@ -0,0 +1,25 @@
/**
* External dependencies
*/
const path = require( 'path' );
/**
* Internal dependencies
*/
const { hasBabelConfig } = require( '../utils' );
const jestUnitConfig = {
preset: '@wordpress/jest-preset-default',
reporters: [
'default',
path.join( __dirname, 'jest-github-actions-reporter', 'index.js' ),
],
};
if ( ! hasBabelConfig() ) {
jestUnitConfig.transform = {
'\\.[jt]sx?$': path.join( __dirname, 'babel-transform' ),
};
}
module.exports = jestUnitConfig;

View File

@@ -0,0 +1,3 @@
{
"extends": "@wordpress/npm-package-json-lint-config"
}

View File

@@ -0,0 +1,60 @@
/**
* External dependencies
*/
const path = require( 'path' );
const { defineConfig, devices } = require( '@playwright/test' );
process.env.WP_ARTIFACTS_PATH ??= path.join( process.cwd(), 'artifacts' );
process.env.STORAGE_STATE_PATH ??= path.join(
process.env.WP_ARTIFACTS_PATH,
'storage-states/admin.json'
);
const config = defineConfig( {
reporter: process.env.CI ? [ [ 'github' ] ] : [ [ 'list' ] ],
forbidOnly: !! process.env.CI,
// fullyParallel: false,
workers: 1,
retries: process.env.CI ? 2 : 0,
timeout: parseInt( process.env.TIMEOUT || '', 10 ) || 100_000, // Defaults to 100 seconds.
// Don't report slow test "files", as we will be running our tests in serial.
reportSlowTests: null,
testDir: './specs',
outputDir: path.join( process.env.WP_ARTIFACTS_PATH, 'test-results' ),
snapshotPathTemplate:
'{testDir}/{testFileDir}/__snapshots__/{arg}-{projectName}{ext}',
globalSetup: require.resolve( './playwright/global-setup.js' ),
use: {
baseURL: process.env.WP_BASE_URL || 'http://localhost:8889',
headless: true,
viewport: {
width: 960,
height: 700,
},
ignoreHTTPSErrors: true,
locale: 'en-US',
contextOptions: {
reducedMotion: 'reduce',
strictSelectors: true,
},
storageState: process.env.STORAGE_STATE_PATH,
actionTimeout: 10_000, // 10 seconds.
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
video: 'on-first-retry',
},
webServer: {
command: 'npm run wp-env start',
port: 8889,
timeout: 120_000, // 120 seconds.
reuseExistingServer: true,
},
projects: [
{
name: 'chromium',
use: { ...devices[ 'Desktop Chrome' ] },
},
],
} );
module.exports = config;

View File

@@ -0,0 +1,35 @@
/**
* External dependencies
*/
const { request } = require( '@playwright/test' );
/**
* WordPress dependencies
*/
const { RequestUtils } = require( '@wordpress/e2e-test-utils-playwright' );
/**
*
* @param {import('@playwright/test').FullConfig} config
* @return {Promise<void>}
*/
async function globalSetup( config ) {
const { storageState, baseURL } = config.projects[ 0 ].use;
const storageStatePath =
typeof storageState === 'string' ? storageState : undefined;
const requestContext = await request.newContext( {
baseURL,
} );
const requestUtils = new RequestUtils( requestContext, {
storageStatePath,
} );
// Authenticate and save the storageState to disk.
await requestUtils.setupRest();
await requestContext.dispose();
}
module.exports = globalSetup;

View File

@@ -0,0 +1,11 @@
module.exports = {
launch: {
devtools: process.env.PUPPETEER_DEVTOOLS === 'true',
headless: process.env.PUPPETEER_HEADLESS !== 'false',
slowMo: parseInt( process.env.PUPPETEER_SLOWMO, 10 ) || 0,
args: [
'--enable-blink-features=ComputedAccessibilityInfo',
'--disable-web-security',
],
},
};

View File

@@ -0,0 +1,477 @@
/**
* External dependencies
*/
const { BundleAnalyzerPlugin } = require( 'webpack-bundle-analyzer' );
const { CleanWebpackPlugin } = require( 'clean-webpack-plugin' );
const CopyWebpackPlugin = require( 'copy-webpack-plugin' );
const webpack = require( 'webpack' );
const browserslist = require( 'browserslist' );
const MiniCSSExtractPlugin = require( 'mini-css-extract-plugin' );
const { basename, dirname, resolve } = require( 'path' );
const ReactRefreshWebpackPlugin = require( '@pmmmwh/react-refresh-webpack-plugin' );
const RtlCssPlugin = require( 'rtlcss-webpack-plugin' );
const TerserPlugin = require( 'terser-webpack-plugin' );
const { realpathSync } = require( 'fs' );
const { sync: glob } = require( 'fast-glob' );
/**
* WordPress dependencies
*/
const DependencyExtractionWebpackPlugin = require( '@wordpress/dependency-extraction-webpack-plugin' );
const postcssPlugins = require( '@wordpress/postcss-plugins-preset' );
/**
* Internal dependencies
*/
const {
fromConfigRoot,
hasBabelConfig,
hasArgInCLI,
hasCssnanoConfig,
hasPostCSSConfig,
getWordPressSrcDirectory,
getWebpackEntryPoints,
getRenderPropPaths,
getAsBooleanFromENV,
getBlockJsonModuleFields,
getBlockJsonScriptFields,
fromProjectRoot,
} = require( '../utils' );
const isProduction = process.env.NODE_ENV === 'production';
const mode = isProduction ? 'production' : 'development';
let target = 'browserslist';
if ( ! browserslist.findConfig( '.' ) ) {
target += ':' + fromConfigRoot( '.browserslistrc' );
}
const hasReactFastRefresh = hasArgInCLI( '--hot' ) && ! isProduction;
const hasExperimentalModulesFlag = getAsBooleanFromENV(
'WP_EXPERIMENTAL_MODULES'
);
/**
* The plugin recomputes the render paths once on each compilation. It is necessary to avoid repeating processing
* when filtering every discovered PHP file in the source folder. This is the most performant way to ensure that
* changes in `block.json` files are picked up in watch mode.
*/
class RenderPathsPlugin {
/**
* Paths with the `render` props included in `block.json` files.
*
* @type {string[]}
*/
static renderPaths;
apply( compiler ) {
const pluginName = this.constructor.name;
compiler.hooks.thisCompilation.tap( pluginName, () => {
this.constructor.renderPaths = getRenderPropPaths();
} );
}
}
const cssLoaders = [
{
loader: MiniCSSExtractPlugin.loader,
},
{
loader: require.resolve( 'css-loader' ),
options: {
importLoaders: 1,
sourceMap: ! isProduction,
modules: {
auto: true,
},
},
},
{
loader: require.resolve( 'postcss-loader' ),
options: {
// Provide a fallback configuration if there's not
// one explicitly available in the project.
...( ! hasPostCSSConfig() && {
postcssOptions: {
ident: 'postcss',
sourceMap: ! isProduction,
plugins: isProduction
? [
...postcssPlugins,
require( 'cssnano' )( {
// Provide a fallback configuration if there's not
// one explicitly available in the project.
...( ! hasCssnanoConfig() && {
preset: [
'default',
{
discardComments: {
removeAll: true,
},
},
],
} ),
} ),
]
: postcssPlugins,
},
} ),
},
},
];
/** @type {webpack.Configuration} */
const baseConfig = {
mode,
target,
output: {
filename: '[name].js',
path: resolve( process.cwd(), 'build' ),
},
resolve: {
alias: {
'lodash-es': 'lodash',
},
extensions: [ '.jsx', '.ts', '.tsx', '...' ],
},
optimization: {
// Only concatenate modules in production, when not analyzing bundles.
concatenateModules: isProduction && ! process.env.WP_BUNDLE_ANALYZER,
splitChunks: {
cacheGroups: {
style: {
type: 'css/mini-extract',
test: /[\\/]style(\.module)?\.(pc|sc|sa|c)ss$/,
chunks: 'all',
enforce: true,
name( _, chunks, cacheGroupKey ) {
const chunkName = chunks[ 0 ].name;
return `${ dirname(
chunkName
) }/${ cacheGroupKey }-${ basename( chunkName ) }`;
},
},
default: false,
},
},
minimizer: [
new TerserPlugin( {
parallel: true,
terserOptions: {
output: {
comments: /translators:/i,
},
compress: {
passes: 2,
},
mangle: {
reserved: [ '__', '_n', '_nx', '_x' ],
},
},
extractComments: false,
} ),
],
},
module: {
rules: [
{
test: /\.m?(j|t)sx?$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve( 'babel-loader' ),
options: {
// Babel uses a directory within local node_modules
// by default. Use the environment variable option
// to enable more persistent caching.
cacheDirectory:
process.env.BABEL_CACHE_DIRECTORY || true,
// Provide a fallback configuration if there's not
// one explicitly available in the project.
...( ! hasBabelConfig() && {
babelrc: false,
configFile: false,
presets: [
require.resolve(
'@wordpress/babel-preset-default'
),
],
plugins: [
hasReactFastRefresh &&
require.resolve(
'react-refresh/babel'
),
].filter( Boolean ),
} ),
},
},
],
},
{
test: /\.css$/,
use: cssLoaders,
},
{
test: /\.pcss$/,
use: cssLoaders,
},
{
test: /\.(sc|sa)ss$/,
use: [
...cssLoaders,
{
loader: require.resolve( 'sass-loader' ),
options: {
sourceMap: ! isProduction,
},
},
],
},
{
test: /\.svg$/,
issuer: /\.(j|t)sx?$/,
use: [ '@svgr/webpack', 'url-loader' ],
type: 'javascript/auto',
},
{
test: /\.svg$/,
issuer: /\.(pc|sc|sa|c)ss$/,
type: 'asset/inline',
},
{
test: /\.(bmp|png|jpe?g|gif|webp)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[name].[hash:8][ext]',
},
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
generator: {
filename: 'fonts/[name].[hash:8][ext]',
},
},
],
},
stats: {
children: false,
},
};
// WP_DEVTOOL global variable controls how source maps are generated.
// See: https://webpack.js.org/configuration/devtool/#devtool.
if ( process.env.WP_DEVTOOL ) {
baseConfig.devtool = process.env.WP_DEVTOOL;
}
if ( ! isProduction ) {
// Set default sourcemap mode if it wasn't set by WP_DEVTOOL.
baseConfig.devtool = baseConfig.devtool || 'source-map';
}
// Add source-map-loader if devtool is set, whether in dev mode or not.
if ( baseConfig.devtool ) {
baseConfig.module.rules.unshift( {
test: /\.(j|t)sx?$/,
exclude: [ /node_modules/ ],
use: require.resolve( 'source-map-loader' ),
enforce: 'pre',
} );
}
/** @type {webpack.Configuration} */
const scriptConfig = {
...baseConfig,
entry: getWebpackEntryPoints( 'script' ),
devServer: isProduction
? undefined
: {
devMiddleware: {
writeToDisk: true,
},
allowedHosts: 'auto',
host: 'localhost',
port: 8887,
proxy: {
'/build': {
pathRewrite: {
'^/build': '',
},
},
},
},
plugins: [
new webpack.DefinePlugin( {
// Inject the `SCRIPT_DEBUG` global, used for development features flagging.
SCRIPT_DEBUG: ! isProduction,
} ),
// If we run a modules build, the 2 compilations can "clean" each other's output
// Prevent the cleaning from happening
! hasExperimentalModulesFlag &&
new CleanWebpackPlugin( {
cleanAfterEveryBuildPatterns: [ '!fonts/**', '!images/**' ],
// Prevent it from deleting webpack assets during builds that have
// multiple configurations returned in the webpack config.
cleanStaleWebpackAssets: false,
} ),
new RenderPathsPlugin(),
new CopyWebpackPlugin( {
patterns: [
{
from: '**/block.json',
context: getWordPressSrcDirectory(),
noErrorOnMissing: true,
transform( content, absoluteFrom ) {
const convertExtension = ( path ) => {
return path.replace( /\.m?(j|t)sx?$/, '.js' );
};
if ( basename( absoluteFrom ) === 'block.json' ) {
const blockJson = JSON.parse( content.toString() );
[
getBlockJsonScriptFields( blockJson ),
getBlockJsonModuleFields( blockJson ),
].forEach( ( fields ) => {
if ( fields ) {
for ( const [
key,
value,
] of Object.entries( fields ) ) {
if ( Array.isArray( value ) ) {
blockJson[ key ] =
value.map( convertExtension );
} else if (
typeof value === 'string'
) {
blockJson[ key ] =
convertExtension( value );
}
}
}
} );
return JSON.stringify( blockJson, null, 2 );
}
return content;
},
},
{
from: '**/*.php',
context: getWordPressSrcDirectory(),
noErrorOnMissing: true,
filter: ( filepath ) => {
return (
process.env.WP_COPY_PHP_FILES_TO_DIST ||
RenderPathsPlugin.renderPaths.includes(
realpathSync( filepath ).replace( /\\/g, '/' )
)
);
},
},
],
} ),
// The WP_BUNDLE_ANALYZER global variable enables a utility that represents
// bundle content as a convenient interactive zoomable treemap.
process.env.WP_BUNDLE_ANALYZER && new BundleAnalyzerPlugin(),
// MiniCSSExtractPlugin to extract the CSS thats gets imported into JavaScript.
new MiniCSSExtractPlugin( { filename: '[name].css' } ),
// RtlCssPlugin to generate RTL CSS files.
new RtlCssPlugin( {
filename: `[name]-rtl.css`,
} ),
// React Fast Refresh.
hasReactFastRefresh && new ReactRefreshWebpackPlugin(),
// WP_NO_EXTERNALS global variable controls whether scripts' assets get
// generated, and the default externals set.
! process.env.WP_NO_EXTERNALS &&
new DependencyExtractionWebpackPlugin(),
].filter( Boolean ),
};
if ( hasExperimentalModulesFlag ) {
/**
* Add block.json files to compilation to ensure changes trigger rebuilds when watching
*/
class BlockJsonDependenciesPlugin {
constructor() {
/** @type {ReadonlyArray<string>} */
this.blockJsonFiles = glob( '**/block.json', {
absolute: true,
cwd: fromProjectRoot( getWordPressSrcDirectory() ),
} );
}
/**
* Apply the plugin
* @param {webpack.Compiler} compiler the compiler instance
* @return {void}
*/
apply( compiler ) {
if ( this.blockJsonFiles.length ) {
compiler.hooks.compilation.tap(
'BlockJsonDependenciesPlugin',
( compilation ) => {
compilation.fileDependencies.addAll(
this.blockJsonFiles
);
}
);
}
}
}
/** @type {webpack.Configuration} */
const moduleConfig = {
...baseConfig,
entry: getWebpackEntryPoints( 'module' ),
experiments: {
...baseConfig.experiments,
outputModule: true,
},
output: {
...baseConfig.output,
module: true,
chunkFormat: 'module',
environment: {
...baseConfig.output.environment,
module: true,
},
library: {
...baseConfig.output.library,
type: 'module',
},
},
plugins: [
new webpack.DefinePlugin( {
// Inject the `SCRIPT_DEBUG` global, used for development features flagging.
SCRIPT_DEBUG: ! isProduction,
} ),
// The WP_BUNDLE_ANALYZER global variable enables a utility that represents
// bundle content as a convenient interactive zoomable treemap.
process.env.WP_BUNDLE_ANALYZER && new BundleAnalyzerPlugin(),
// MiniCSSExtractPlugin to extract the CSS thats gets imported into JavaScript.
new MiniCSSExtractPlugin( { filename: '[name].css' } ),
// WP_NO_EXTERNALS global variable controls whether scripts' assets get
// generated, and the default externals set.
! process.env.WP_NO_EXTERNALS &&
new DependencyExtractionWebpackPlugin(),
new BlockJsonDependenciesPlugin(),
].filter( Boolean ),
};
module.exports = [ scriptConfig, moduleConfig ];
} else {
module.exports = scriptConfig;
}

103
node_modules/@wordpress/scripts/package.json generated vendored Normal file
View File

@@ -0,0 +1,103 @@
{
"name": "@wordpress/scripts",
"version": "27.9.0",
"description": "Collection of reusable scripts for WordPress development.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
"keywords": [
"wordpress",
"gutenberg",
"scripts"
],
"homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/packages/scripts/README.md",
"repository": {
"type": "git",
"url": "https://github.com/WordPress/gutenberg.git",
"directory": "packages/scripts"
},
"bugs": {
"url": "https://github.com/WordPress/gutenberg/issues"
},
"engines": {
"node": ">=18",
"npm": ">=6.14.4"
},
"files": [
"bin",
"config",
"scripts",
"utils"
],
"bin": {
"wp-scripts": "./bin/wp-scripts.js"
},
"dependencies": {
"@babel/core": "^7.16.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
"@svgr/webpack": "^8.0.1",
"@wordpress/babel-preset-default": "^7.42.0",
"@wordpress/browserslist-config": "^5.41.0",
"@wordpress/dependency-extraction-webpack-plugin": "^5.9.0",
"@wordpress/e2e-test-utils-playwright": "^0.26.0",
"@wordpress/eslint-plugin": "^18.1.0",
"@wordpress/jest-preset-default": "^11.29.0",
"@wordpress/npm-package-json-lint-config": "^4.43.0",
"@wordpress/postcss-plugins-preset": "^4.42.0",
"@wordpress/prettier-config": "^3.15.0",
"@wordpress/stylelint-config": "^21.41.0",
"adm-zip": "^0.5.9",
"babel-jest": "^29.6.2",
"babel-loader": "^8.2.3",
"browserslist": "^4.21.10",
"chalk": "^4.0.0",
"check-node-version": "^4.1.0",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^10.2.0",
"cross-spawn": "^5.1.0",
"css-loader": "^6.2.0",
"cssnano": "^6.0.1",
"cwd": "^0.10.0",
"dir-glob": "^3.0.1",
"eslint": "^8.3.0",
"expect-puppeteer": "^4.4.0",
"fast-glob": "^3.2.7",
"filenamify": "^4.2.0",
"jest": "^29.6.2",
"jest-dev-server": "^9.0.1",
"jest-environment-jsdom": "^29.6.2",
"jest-environment-node": "^29.6.2",
"markdownlint-cli": "^0.31.1",
"merge-deep": "^3.0.3",
"mini-css-extract-plugin": "^2.5.1",
"minimist": "^1.2.0",
"npm-package-json-lint": "^6.4.0",
"npm-packlist": "^3.0.0",
"postcss": "^8.4.5",
"postcss-loader": "^6.2.1",
"prettier": "npm:wp-prettier@3.0.3",
"puppeteer-core": "^13.2.0",
"react-refresh": "^0.14.0",
"read-pkg-up": "^7.0.1",
"resolve-bin": "^0.4.0",
"rtlcss-webpack-plugin": "^4.0.7",
"sass": "^1.35.2",
"sass-loader": "^12.1.0",
"source-map-loader": "^3.0.0",
"stylelint": "^14.2.0",
"terser-webpack-plugin": "^5.3.9",
"url-loader": "^4.1.1",
"webpack": "^5.88.2",
"webpack-bundle-analyzer": "^4.9.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"peerDependencies": {
"@playwright/test": "^1.43.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"publishConfig": {
"access": "public"
},
"gitHead": "42f38f287506a6b3ed8ccba839b18ad066821044"
}

38
node_modules/@wordpress/scripts/scripts/build.js generated vendored Normal file
View File

@@ -0,0 +1,38 @@
/**
* External dependencies
*/
const { sync: spawn } = require( 'cross-spawn' );
const { sync: resolveBin } = require( 'resolve-bin' );
/**
* Internal dependencies
*/
const { getWebpackArgs, hasArgInCLI, getArgFromCLI } = require( '../utils' );
const EXIT_ERROR_CODE = 1;
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
if ( hasArgInCLI( '--experimental-modules' ) ) {
process.env.WP_EXPERIMENTAL_MODULES = true;
}
if ( hasArgInCLI( '--webpack-no-externals' ) ) {
process.env.WP_NO_EXTERNALS = true;
}
if ( hasArgInCLI( '--webpack-bundle-analyzer' ) ) {
process.env.WP_BUNDLE_ANALYZER = true;
}
if ( hasArgInCLI( '--webpack-copy-php' ) ) {
process.env.WP_COPY_PHP_FILES_TO_DIST = true;
}
process.env.WP_SRC_DIRECTORY = hasArgInCLI( '--webpack-src-dir' )
? getArgFromCLI( '--webpack-src-dir' )
: 'src';
const { status } = spawn( resolveBin( 'webpack' ), getWebpackArgs(), {
stdio: 'inherit',
} );
process.exit( status === null ? EXIT_ERROR_CODE : status );

View File

@@ -0,0 +1,36 @@
/**
* External dependencies
*/
const { sync: spawn } = require( 'cross-spawn' );
const { sync: resolveBin } = require( 'resolve-bin' );
/**
* Internal dependencies
*/
const { getArgsFromCLI, hasArgInCLI, getPackageProp } = require( '../utils' );
const getConfig = () => {
const hasConfig =
hasArgInCLI( '--package' ) ||
hasArgInCLI( '--node' ) ||
hasArgInCLI( '--npm' ) ||
hasArgInCLI( '--yarn' );
if ( hasConfig ) {
return [];
}
const { node, npm } =
getPackageProp( 'engines' ) || require( '../package.json' ).engines;
return [ '--node', node, '--npm', npm ];
};
const result = spawn(
resolveBin( 'check-node-version' ),
[ ...getConfig(), ...getArgsFromCLI() ],
{
stdio: 'inherit',
}
);
process.exit( result.status );

View File

@@ -0,0 +1,385 @@
/**
* External dependencies
*/
const spawn = require( 'cross-spawn' );
const { existsSync, readFileSync } = require( 'fs' );
const chalk = require( 'chalk' );
/**
* Internal dependencies
*/
const { getArgFromCLI, hasArgInCLI } = require( '../utils' );
/*
* WARNING: Changes to this file may inadvertently cause us to distribute code that
* is not GPL2 compatible.
*
* When adding a new license (for example, when a new package has a variation of the
* various license strings), please ensure that changes to this file are explicitly
* reviewed and approved.
*/
const ERROR = chalk.reset.inverse.bold.red( ' ERROR ' );
const WARNING = chalk.reset.inverse.bold.yellow( ' WARNING ' );
const prod = hasArgInCLI( '--prod' ) || hasArgInCLI( '--production' );
const dev = hasArgInCLI( '--dev' ) || hasArgInCLI( '--development' );
const gpl2 = hasArgInCLI( '--gpl2' );
const ignored = hasArgInCLI( '--ignore' )
? getArgFromCLI( '--ignore' )
// "--ignore=a, b" -> "[ 'a', ' b' ]"
.split( ',' )
// "[ 'a', ' b' ]" -> "[ 'a', 'b' ]"
.map( ( moduleName ) => moduleName.trim() )
: [];
/*
* A list of license strings that we've found to be GPL2 compatible.
*
* Note the strings with "AND" in them at the bottom: these should only be added when
* all the licenses in that string are GPL2 compatible.
*/
const gpl2CompatibleLicenses = [
'0BSD',
'Apache-2.0 WITH LLVM-exception',
'Artistic-2.0',
'BSD-2-Clause',
'BSD-3-Clause-W3C',
'BSD-3-Clause',
'BSD',
'CC-BY-4.0',
'CC0-1.0',
'GPL-2.0-or-later',
'GPL-2.0',
'GPL-2.0+',
'ISC',
'LGPL-2.1',
'MIT',
'MIT/X11',
'MPL-2.0',
'ODC-By-1.0',
'Public Domain',
'Unlicense',
'W3C-20150513',
'WTFPL',
'Zlib',
];
/*
* A list of OSS license strings that aren't GPL2 compatible.
*
* We're cool with using packages that are licensed under any of these if we're not
* distributing them (for example, build tools), but we can't included them in a release.
*/
const otherOssLicenses = [
'Apache-2.0',
'Apache License, Version 2.0',
'CC-BY-3.0',
'CC-BY-SA-2.0',
'LGPL',
'Python-2.0',
];
const licenses = [
...gpl2CompatibleLicenses,
...( gpl2 ? [] : otherOssLicenses ),
];
/*
* Some packages don't included a license string in their package.json file, but they
* do have a license listed elsewhere. These files are checked for matching license strings.
* Only the first matching license file with a matching license string is considered.
*
* See: licenseFileStrings.
*/
const licenseFiles = [
'LICENCE',
'license',
'LICENSE',
'LICENSE.md',
'LICENSE.txt',
'LICENSE-MIT',
'MIT-LICENSE.txt',
'Readme.md',
'README.md',
];
/*
* When searching through files for licensing information, these are the strings we look for,
* and their matching license.
*/
const licenseFileStrings = {
'Apache-2.0': [ 'Licensed under the Apache License, Version 2.0' ],
BSD: [
'Redistributions in binary form must reproduce the above copyright notice,',
],
'BSD-3-Clause-W3C': [ 'W3C 3-clause BSD License' ],
MIT: [
'Permission is hereby granted, free of charge,',
'## License\n\nMIT',
'## License\n\n MIT',
],
};
/**
* Check if a license string matches the given license.
*
* The license string can be a single license, or an SPDX-compatible "OR" license string.
* eg, "(MIT OR Zlib)".
*
* @param {string} allowedLicense The license that's allowed.
* @param {string} licenseType The license string to check.
*
* @return {boolean} true if the licenseType matches the allowedLicense, false if it doesn't.
*/
const checkLicense = ( allowedLicense, licenseType ) => {
if ( ! licenseType ) {
return false;
}
// Some licenses have unusual capitalisation in them.
const formattedAllowedLicense = allowedLicense.toLowerCase();
const formattedlicenseType = licenseType.toLowerCase();
if ( formattedAllowedLicense === formattedlicenseType ) {
return true;
}
// We can skip the parsing below if there isn't an 'OR' in the license.
if ( ! formattedlicenseType.includes( ' or ' ) ) {
return false;
}
/*
* In order to do a basic parse of SPDX-compatible "OR" license strings, we:
* - Remove surrounding brackets: "(mit or zlib)" -> "mit or zlib"
* - Split it into an array: "mit or zlib" -> [ "mit", "zlib" ]
* - Trim any remaining whitespace from each element
*/
const subLicenseTypes = formattedlicenseType
.replace( /^\(*/g, '' )
.replace( /\)*$/, '' )
.split( ' or ' )
.map( ( e ) => e.trim() );
// We can then check our array of licenses against the allowedLicense.
return (
undefined !==
subLicenseTypes.find( ( subLicenseType ) =>
checkLicense( allowedLicense, subLicenseType )
)
);
};
// Use `npm ls` to grab a list of all the packages.
const child = spawn.sync(
'npm',
[
'ls',
'--json',
'--long',
'--all',
...( prod ? [ '--prod' ] : [] ),
...( dev ? [ '--dev' ] : [] ),
],
/*
* Set the max buffer to ~157MB, since the output size for
* prod is ~21 MB and dev is ~110 MB
*/
{ maxBuffer: 1024 * 1024 * 150 }
);
const result = JSON.parse( child.stdout.toString() );
const topLevelDeps = result.dependencies;
function traverseDepTree( deps ) {
for ( const key in deps ) {
const dep = deps[ key ];
if ( ignored.includes( dep.name ) ) {
return;
}
if ( ! dep.hasOwnProperty( 'path' ) ) {
if ( dep.hasOwnProperty( 'peerMissing' ) ) {
process.stdout.write(
`${ WARNING } Unable to locate path for missing peer dep ${ dep.name }@${ dep.version }. `
);
} else {
process.exitCode = 1;
process.stdout.write(
`${ ERROR } Unable to locate path for ${ dep.name }@${ dep.version }. `
);
}
} else if ( dep.missing ) {
process.stdout.write(
`${ WARNING } missing dep ${ dep.name }@${ dep.version }. `
);
} else {
checkDepLicense( dep.path );
}
if ( dep.hasOwnProperty( 'dependencies' ) ) {
traverseDepTree( dep.dependencies );
} else {
return;
}
}
}
function detectTypeFromLicenseFiles( path ) {
return licenseFiles.reduce( ( detectedType, licenseFile ) => {
// If another LICENSE file already had licenses in it, use those.
if ( detectedType ) {
return detectedType;
}
const licensePath = path + '/' + licenseFile;
if ( existsSync( licensePath ) ) {
const licenseText = readFileSync( licensePath ).toString();
return detectTypeFromLicenseText( licenseText );
}
return detectedType;
}, false );
}
function detectTypeFromLicenseText( licenseText ) {
// Check if the file contains any of the strings in licenseFileStrings.
return Object.keys( licenseFileStrings ).reduce(
( stringDetectedType, licenseStringType ) => {
const licenseFileString = licenseFileStrings[ licenseStringType ];
return licenseFileString.reduce(
( currentDetectedType, fileString ) => {
if ( licenseText.includes( fileString ) ) {
if ( currentDetectedType ) {
return currentDetectedType.concat(
' AND ',
licenseStringType
);
}
return licenseStringType;
}
return currentDetectedType;
},
stringDetectedType
);
},
false
);
}
function checkDepLicense( path ) {
if ( ! path ) {
return;
}
const filename = path + '/package.json';
if ( ! existsSync( filename ) ) {
process.stdout.write( `Unable to locate package.json in ${ path }.` );
process.exit( 1 );
}
/*
* The package.json format can be kind of weird. We allow for the following formats:
* - { license: 'MIT' }
* - { license: { type: 'MIT' } }
* - { licenses: [ 'MIT', 'Zlib' ] }
* - { licenses: [ { type: 'MIT' }, { type: 'Zlib' } ] }
*/
const packageInfo = require( filename );
const license =
packageInfo.license ||
( packageInfo.licenses &&
packageInfo.licenses.map( ( l ) => l.type || l ).join( ' OR ' ) );
let licenseType = typeof license === 'object' ? license.type : license;
// Check if the license we've detected is telling us to look in the license file, instead.
if (
licenseType &&
licenseFiles.find( ( licenseFile ) =>
licenseType.includes( licenseFile )
)
) {
licenseType = undefined;
}
if ( licenseType !== undefined ) {
let licenseTypes = [ licenseType ];
if ( licenseType.includes( ' AND ' ) ) {
licenseTypes = licenseType
.replace( /^\(*/g, '' )
.replace( /\)*$/, '' )
.split( ' AND ' )
.map( ( e ) => e.trim() );
}
if ( checkAllCompatible( licenseTypes, licenses ) ) {
return;
}
}
/*
* If we haven't been able to detect a license in the package.json file,
* or the type was invalid, try reading it from the files defined in
* license files, instead.
*/
const detectedLicenseType = detectTypeFromLicenseFiles( path );
if ( ! licenseType && ! detectedLicenseType ) {
return;
}
let detectedLicenseTypes = [ detectedLicenseType ];
if ( detectedLicenseType.includes( ' AND ' ) ) {
detectedLicenseTypes = detectedLicenseType
.replace( /^\(*/g, '' )
.replace( /\)*$/, '' )
.split( ' AND ' )
.map( ( e ) => e.trim() );
}
if ( checkAllCompatible( detectedLicenseTypes, licenses ) ) {
return;
}
process.exitCode = 1;
process.stdout.write(
`${ ERROR } Module ${ packageInfo.name } has an incompatible license '${ licenseType }'.\n`
);
}
/**
* Check that all of the licenses for a package are compatible.
*
* This function is invoked when the licenses are a conjunctive ("AND") list of licenses.
* In that case, the software is only compatible if all of the licenses in the list are
* compatible.
*
* @param {Array} packageLicenses The licenses that a package is licensed under.
* @param {Array} compatibleLicenses The list of compatible licenses.
*
* @return {boolean} true if all of the packageLicenses appear in compatibleLicenses.
*/
function checkAllCompatible( packageLicenses, compatibleLicenses ) {
return packageLicenses.reduce( ( compatible, packageLicense ) => {
return (
compatible &&
compatibleLicenses.reduce(
( found, allowedLicense ) =>
found || checkLicense( allowedLicense, packageLicense ),
false
)
);
}, true );
}
traverseDepTree( topLevelDeps );
// Required for unit testing
module.exports = {
detectTypeFromLicenseText,
checkAllCompatible,
};

14
node_modules/@wordpress/scripts/scripts/env.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
/**
* External dependencies
*/
const chalk = require( 'chalk' );
process.stdout.write(
chalk.yellow(
'The `env` family of scripts has been deprecated. Please use `wp-env` instead.'
)
);
process.stdout.write(
chalk.blue( '\nSee: https://www.npmjs.com/package/@wordpress/env\n' )
);
process.exit( 1 );

116
node_modules/@wordpress/scripts/scripts/format.js generated vendored Normal file
View File

@@ -0,0 +1,116 @@
/**
* External dependencies
*/
const { exit, stdout } = require( 'process' );
/**
* External dependencies
*/
const chalk = require( 'chalk' );
const { sync: spawn } = require( 'cross-spawn' );
const { sync: resolveBin } = require( 'resolve-bin' );
const { sync: dirGlob } = require( 'dir-glob' );
const { sync: readPkgUp } = require( 'read-pkg-up' );
/**
* Internal dependencies
*/
const {
fromConfigRoot,
fromProjectRoot,
getArgFromCLI,
getFileArgsFromCLI,
hasArgInCLI,
hasPrettierConfig,
hasProjectFile,
} = require( '../utils' );
// Check if the project has wp-prettier installed and if the project has a Prettier config.
function checkPrettier() {
try {
const prettierResolvePath = require.resolve( 'prettier' );
const prettierPackageJson = readPkgUp( { cwd: prettierResolvePath } );
const prettierPackageName = prettierPackageJson.packageJson.name;
if (
! [ 'wp-prettier', '@wordpress/prettier' ].includes(
prettierPackageName
)
) {
return {
success: false,
message:
chalk.red(
'Incompatible version of Prettier was found in your project\n'
) +
"You need to install the 'wp-prettier' package to get " +
'code formatting compliant with the WordPress coding standards.\n\n',
};
}
} catch {
return {
success: false,
message:
chalk.red(
"The 'prettier' package was not found in your project\n"
) +
"You need to install the 'wp-prettier' package under an alias to get " +
'code formatting compliant with the WordPress coding standards.\n\n',
};
}
return { success: true };
}
const checkResult = checkPrettier();
if ( ! checkResult.success ) {
stdout.write( checkResult.message );
exit( 1 );
}
// Check for existing config in project, if it exists no command-line args are
// needed for config, otherwise pass in args to default config in packages
// See: https://prettier.io/docs/en/configuration.html
let configArgs = [];
if ( ! hasPrettierConfig() ) {
configArgs = [
'--config',
require.resolve( '@wordpress/prettier-config' ),
];
}
// If `--ignore-path` is not explicitly specified, use the project's or global .prettierignore.
let ignorePath = getArgFromCLI( '--ignore-path' );
if ( ! ignorePath ) {
if ( hasProjectFile( '.prettierignore' ) ) {
ignorePath = fromProjectRoot( '.prettierignore' );
} else {
ignorePath = fromConfigRoot( '.prettierignore' );
}
}
const ignoreArgs = [ '--ignore-path', ignorePath ];
// Forward the --require-pragma option that formats only files that already have the @format
// pragma in the first docblock.
const pragmaArgs = hasArgInCLI( '--require-pragma' )
? [ '--require-pragma' ]
: [];
// Get the files and directories to format and convert them to globs.
let fileArgs = getFileArgsFromCLI();
if ( fileArgs.length === 0 ) {
fileArgs = [ '.' ];
}
// Converts `foo/bar` directory to `foo/bar/**/*.js`
const globArgs = dirGlob( fileArgs, {
extensions: [ 'js', 'jsx', 'json', 'ts', 'tsx', 'yml', 'yaml' ],
} );
const result = spawn(
resolveBin( 'prettier' ),
[ '--write', ...configArgs, ...ignoreArgs, ...pragmaArgs, ...globArgs ],
{ stdio: 'inherit' }
);
process.exit( result.status );

66
node_modules/@wordpress/scripts/scripts/lint-js.js generated vendored Normal file
View File

@@ -0,0 +1,66 @@
/**
* External dependencies
*/
const { sync: spawn } = require( 'cross-spawn' );
const { sync: resolveBin } = require( 'resolve-bin' );
/**
* Internal dependencies
*/
const {
fromConfigRoot,
getArgsFromCLI,
hasArgInCLI,
hasFileArgInCLI,
hasPackageProp,
hasProjectFile,
} = require( '../utils' );
const args = getArgsFromCLI();
const defaultFilesArgs = hasFileArgInCLI() ? [] : [ '.' ];
// See: https://eslint.org/docs/user-guide/configuring#using-configuration-files-1.
const hasLintConfig =
hasArgInCLI( '-c' ) ||
hasArgInCLI( '--config' ) ||
hasProjectFile( '.eslintrc.js' ) ||
hasProjectFile( '.eslintrc.json' ) ||
hasProjectFile( '.eslintrc.yaml' ) ||
hasProjectFile( '.eslintrc.yml' ) ||
hasProjectFile( 'eslintrc.config.js' ) ||
hasProjectFile( '.eslintrc' ) ||
hasPackageProp( 'eslintConfig' );
// When a configuration is not provided by the project, use from the default
// provided with the scripts module. Instruct ESLint to avoid discovering via
// the `--no-eslintrc` flag, as otherwise it will still merge with inherited.
const defaultConfigArgs = ! hasLintConfig
? [ '--no-eslintrc', '--config', fromConfigRoot( '.eslintrc.js' ) ]
: [];
// See: https://eslint.org/docs/user-guide/configuring#ignoring-files-and-directories.
const hasIgnoredFiles =
hasArgInCLI( '--ignore-path' ) || hasProjectFile( '.eslintignore' );
const defaultIgnoreArgs = ! hasIgnoredFiles
? [ '--ignore-path', fromConfigRoot( '.eslintignore' ) ]
: [];
const defaultExtArgs = hasArgInCLI( '--ext' )
? []
: [ '--ext', 'js,jsx,ts,tsx' ];
const result = spawn(
resolveBin( 'eslint' ),
[
...defaultConfigArgs,
...defaultIgnoreArgs,
...defaultExtArgs,
...args,
...defaultFilesArgs,
],
{ stdio: 'inherit' }
);
process.exit( result.status );

View File

@@ -0,0 +1,61 @@
/**
* External dependencies
*/
const { sync: spawn } = require( 'cross-spawn' );
const { sync: resolveBin } = require( 'resolve-bin' );
/**
* Internal dependencies
*/
const {
fromConfigRoot,
getArgsFromCLI,
hasArgInCLI,
hasFileArgInCLI,
hasProjectFile,
} = require( '../utils' );
const args = getArgsFromCLI();
const defaultFilesArgs = hasFileArgInCLI() ? [] : [ '**/*.md' ];
// See: https://github.com/igorshubovych/markdownlint-cli#configuration
// Check if specified on command-line or project file for config.
const hasLintConfig =
hasArgInCLI( '-c' ) ||
hasArgInCLI( '--config' ) ||
hasProjectFile( '.markdownlint.json' ) ||
hasProjectFile( '.markdownlint.yaml' ) ||
hasProjectFile( '.markdownlint.yml' ) ||
hasProjectFile( '.markdownlintrc' );
// When a configuration is not provided by the project, use from the default
// provided with the scripts module.
const defaultConfigArgs = ! hasLintConfig
? [ '--config', fromConfigRoot( '.markdownlint.json' ) ]
: [];
// See: https://github.com/igorshubovych/markdownlint-cli#ignoring-files
// Check if ignore specified on command-line or project file.
const hasIgnoredFiles =
hasArgInCLI( '--ignore' ) ||
hasArgInCLI( '-i' ) ||
hasProjectFile( '.markdownlintignore' );
// Default ignore [ build, node_modules ] directories.
const defaultIgnoreArgs = ! hasIgnoredFiles
? [ '--ignore-path', fromConfigRoot( '.markdownlintignore' ) ]
: [];
const result = spawn(
resolveBin( 'markdownlint-cli', { executable: 'markdownlint' } ),
[
...defaultConfigArgs,
...defaultIgnoreArgs,
...args,
...defaultFilesArgs,
],
{ stdio: 'inherit' }
);
process.exit( result.status );

View File

@@ -0,0 +1,61 @@
/**
* External dependencies
*/
const { sync: spawn } = require( 'cross-spawn' );
const { sync: resolveBin } = require( 'resolve-bin' );
/**
* Internal dependencies
*/
const {
fromConfigRoot,
getArgsFromCLI,
hasArgInCLI,
hasFileArgInCLI,
hasProjectFile,
hasPackageProp,
} = require( '../utils' );
const args = getArgsFromCLI();
const defaultFilesArgs = hasFileArgInCLI() ? [] : [ '.' ];
// See: https://npmpackagejsonlint.org/docs/en/configuration
const hasLintConfig =
hasArgInCLI( '-c' ) ||
hasArgInCLI( '--configFile' ) ||
hasProjectFile( '.npmpackagejsonlintrc.js' ) ||
hasProjectFile( '.npmpackagejsonlintrc.json' ) ||
hasProjectFile( '.npmpackagejsonlintrc.yaml' ) ||
hasProjectFile( '.npmpackagejsonlintrc.yml' ) ||
hasProjectFile( 'npmpackagejsonlint.config.js' ) ||
hasProjectFile( '.npmpackagejsonlintrc' ) ||
hasPackageProp( 'npmpackagejsonlint' ) ||
// npm-package-json-lint v3.x used a different prop name.
hasPackageProp( 'npmPackageJsonLintConfig' );
const defaultConfigArgs = ! hasLintConfig
? [ '--configFile', fromConfigRoot( 'npmpackagejsonlint.json' ) ]
: [];
// See: https://github.com/tclindner/npm-package-json-lint/#cli-commands-and-configuration.
const hasIgnoredFiles =
hasArgInCLI( '--ignorePath' ) ||
hasProjectFile( '.npmpackagejsonlintignore' );
const defaultIgnoreArgs = ! hasIgnoredFiles
? [ '--ignorePath', fromConfigRoot( '.npmpackagejsonlintignore' ) ]
: [];
const result = spawn(
resolveBin( 'npm-package-json-lint', { executable: 'npmPkgJsonLint' } ),
[
...defaultConfigArgs,
...defaultIgnoreArgs,
...args,
...defaultFilesArgs,
],
{ stdio: 'inherit' }
);
process.exit( result.status );

57
node_modules/@wordpress/scripts/scripts/lint-style.js generated vendored Normal file
View File

@@ -0,0 +1,57 @@
/**
* External dependencies
*/
const { sync: spawn } = require( 'cross-spawn' );
const { sync: resolveBin } = require( 'resolve-bin' );
/**
* Internal dependencies
*/
const {
fromConfigRoot,
getArgsFromCLI,
hasArgInCLI,
hasFileArgInCLI,
hasProjectFile,
hasPackageProp,
} = require( '../utils' );
const args = getArgsFromCLI();
const defaultFilesArgs = hasFileArgInCLI() ? [] : [ '**/*.{css,pcss,scss}' ];
// See: https://stylelint.io/user-guide/configuration
const hasLintConfig =
hasArgInCLI( '--config' ) ||
hasProjectFile( '.stylelintrc.js' ) ||
hasProjectFile( '.stylelintrc.json' ) ||
hasProjectFile( '.stylelintrc.yaml' ) ||
hasProjectFile( '.stylelintrc.yml' ) ||
hasProjectFile( 'stylelint.config.js' ) ||
hasProjectFile( '.stylelintrc' ) ||
hasPackageProp( 'stylelint' );
const defaultConfigArgs = ! hasLintConfig
? [ '--config', fromConfigRoot( '.stylelintrc.json' ) ]
: [];
// See: https://github.com/stylelint/stylelint/blob/HEAD/docs/user-guide/ignore-code.md#files-entirely.
const hasIgnoredFiles =
hasArgInCLI( '--ignore-path' ) || hasProjectFile( '.stylelintignore' );
const defaultIgnoreArgs = ! hasIgnoredFiles
? [ '--ignore-path', fromConfigRoot( '.stylelintignore' ) ]
: [];
const result = spawn(
resolveBin( 'stylelint' ),
[
...defaultConfigArgs,
...defaultIgnoreArgs,
...args,
...defaultFilesArgs,
],
{ stdio: 'inherit' }
);
process.exit( result.status );

View File

@@ -0,0 +1,85 @@
/* eslint-disable no-console */
/**
* External dependencies
*/
const fs = require( 'fs' );
const spawn = require( 'cross-spawn' );
/**
* Internal dependencies
*/
const { getArgFromCLI } = require( '../utils' );
/**
* Constants
*/
const WORDPRESS_PACKAGES_PREFIX = '@wordpress/';
function readJSONFile( fileName ) {
const data = fs.readFileSync( fileName, 'utf8' );
return JSON.parse( data );
}
function getWordPressPackages( { dependencies = {}, devDependencies = {} } ) {
return Object.keys( dependencies )
.concat( Object.keys( devDependencies ) )
.filter( ( packageName ) =>
packageName.startsWith( WORDPRESS_PACKAGES_PREFIX )
);
}
function getPackageVersionDiff( initialPackageJSON, finalPackageJSON ) {
const diff = [ 'dependencies', 'devDependencies' ].reduce(
( result, keyPackageJSON ) => {
return Object.keys(
finalPackageJSON[ keyPackageJSON ] || {}
).reduce( ( _result, dependency ) => {
const initial =
initialPackageJSON[ keyPackageJSON ][ dependency ];
const final = finalPackageJSON[ keyPackageJSON ][ dependency ];
if ( initial !== final ) {
_result.push( { dependency, initial, final } );
}
return _result;
}, result );
},
[]
);
return diff.sort( ( a, b ) => a.dependency.localeCompare( b.dependency ) );
}
function updatePackagesToLatestVersion( packages ) {
const distTag = getArgFromCLI( '--dist-tag' ) || 'latest';
const packagesWithLatest = packages.map(
( packageName ) => `${ packageName }@${ distTag }`
);
return spawn.sync( 'npm', [ 'install', ...packagesWithLatest, '--save' ], {
stdio: 'inherit',
} );
}
function outputPackageDiffReport( packageDiff ) {
console.log(
[
'The following package versions were changed:',
...packageDiff.map( ( { dependency, initial, final } ) => {
return `${ dependency }: ${ initial } -> ${ final }`;
} ),
].join( '\n' )
);
}
function updatePackageJSON() {
const initialPackageJSON = readJSONFile( 'package.json' );
const packages = getWordPressPackages( initialPackageJSON );
const result = updatePackagesToLatestVersion( packages );
const finalPackageJSON = readJSONFile( 'package.json' );
outputPackageDiffReport(
getPackageVersionDiff( initialPackageJSON, finalPackageJSON )
);
process.exit( result.status );
}
updatePackageJSON();
/* eslint-enable no-console */

57
node_modules/@wordpress/scripts/scripts/plugin-zip.js generated vendored Normal file
View File

@@ -0,0 +1,57 @@
/**
* External dependencies
*/
const AdmZip = require( 'adm-zip' );
const { sync: glob } = require( 'fast-glob' );
const { sync: packlist } = require( 'npm-packlist' );
const { dirname } = require( 'path' );
const { stdout } = require( 'process' );
/**
* Internal dependencies
*/
const { hasPackageProp, getPackageProp } = require( '../utils' );
const name = getPackageProp( 'name' );
stdout.write( `Creating archive for \`${ name }\` plugin... 🎁\n\n` );
const zip = new AdmZip();
let files = [];
if ( hasPackageProp( 'files' ) ) {
stdout.write(
'Using the `files` field from `package.json` to detect files:\n\n'
);
files = packlist();
} else {
stdout.write(
'Using Plugin Handbook best practices to discover files:\n\n'
);
// See https://developer.wordpress.org/plugins/plugin-basics/best-practices/#file-organization.
files = glob(
[
'admin/**',
'build/**',
'includes/**',
'languages/**',
'public/**',
`${ name }.php`,
'uninstall.php',
'block.json',
'changelog.*',
'license.*',
'readme.*',
],
{
caseSensitiveMatch: false,
}
);
}
files.forEach( ( file ) => {
stdout.write( ` Adding \`${ file }\`.\n` );
const zipDirectory = dirname( file );
zip.addLocalFile( file, zipDirectory !== '.' ? zipDirectory : '' );
} );
zip.writeZip( `./${ name }.zip` );
stdout.write( `\nDone. \`${ name }.zip\` is ready! 🎉\n` );

47
node_modules/@wordpress/scripts/scripts/start.js generated vendored Normal file
View File

@@ -0,0 +1,47 @@
/**
* External dependencies
*/
const { sync: spawn } = require( 'cross-spawn' );
const { sync: resolveBin } = require( 'resolve-bin' );
/**
* Internal dependencies
*/
const { getArgFromCLI, getWebpackArgs, hasArgInCLI } = require( '../utils' );
const EXIT_ERROR_CODE = 1;
if ( hasArgInCLI( '--experimental-modules' ) ) {
process.env.WP_EXPERIMENTAL_MODULES = true;
}
if ( hasArgInCLI( '--webpack-no-externals' ) ) {
process.env.WP_NO_EXTERNALS = true;
}
if ( hasArgInCLI( '--webpack-bundle-analyzer' ) ) {
process.env.WP_BUNDLE_ANALYZER = true;
}
if ( hasArgInCLI( '--webpack--devtool' ) ) {
process.env.WP_DEVTOOL = getArgFromCLI( '--webpack--devtool' );
}
if ( hasArgInCLI( '--webpack-copy-php' ) ) {
process.env.WP_COPY_PHP_FILES_TO_DIST = true;
}
process.env.WP_SRC_DIRECTORY = hasArgInCLI( '--webpack-src-dir' )
? getArgFromCLI( '--webpack-src-dir' )
: 'src';
const webpackArgs = getWebpackArgs();
if ( hasArgInCLI( '--hot' ) ) {
webpackArgs.unshift( 'serve' );
} else if ( ! hasArgInCLI( '--no-watch' ) ) {
webpackArgs.unshift( 'watch' );
}
const { status } = spawn( resolveBin( 'webpack' ), webpackArgs, {
stdio: 'inherit',
} );
process.exit( status === null ? EXIT_ERROR_CODE : status );

91
node_modules/@wordpress/scripts/scripts/test-e2e.js generated vendored Normal file
View File

@@ -0,0 +1,91 @@
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on( 'unhandledRejection', ( err ) => {
throw err;
} );
/**
* External dependencies
*/
const path = require( 'path' );
const jest = require( 'jest' );
const { sync: spawn } = require( 'cross-spawn' );
/**
* Internal dependencies
*/
const {
getJestOverrideConfigFile,
fromConfigRoot,
getArgFromCLI,
getArgsFromCLI,
hasArgInCLI,
hasProjectFile,
} = require( '../utils' );
const result = spawn( 'node', [ require.resolve( 'puppeteer-core/install' ) ], {
stdio: 'inherit',
} );
if ( result.status > 0 ) {
process.exit( result.status );
}
// Provides a default config path for Puppeteer when jest-puppeteer.config.js
// wasn't found at the root of the project or a custom path wasn't defined
// using JEST_PUPPETEER_CONFIG environment variable.
if (
! hasProjectFile( 'jest-puppeteer.config.js' ) &&
! process.env.JEST_PUPPETEER_CONFIG
) {
process.env.JEST_PUPPETEER_CONFIG = fromConfigRoot( 'puppeteer.config.js' );
}
const configFile = getJestOverrideConfigFile( 'e2e' );
const config = configFile
? [ '--config', JSON.stringify( require( configFile ) ) ]
: [];
// Force e2e tests to run serially, not in parallel. They test against a shared Docker instance
const hasRunInBand = hasArgInCLI( '--runInBand' ) || hasArgInCLI( '-i' );
const runInBand = ! hasRunInBand ? [ '--runInBand' ] : [];
if ( hasArgInCLI( '--puppeteer-interactive' ) ) {
process.env.PUPPETEER_HEADLESS = 'false';
process.env.PUPPETEER_SLOWMO = getArgFromCLI( '--puppeteer-slowmo' ) || 80;
}
if ( hasArgInCLI( '--puppeteer-devtools' ) ) {
process.env.PUPPETEER_HEADLESS = 'false';
process.env.PUPPETEER_DEVTOOLS = 'true';
}
const configsMapping = {
WP_BASE_URL: '--wordpress-base-url',
WP_USERNAME: '--wordpress-username',
WP_PASSWORD: '--wordpress-password',
};
Object.entries( configsMapping ).forEach( ( [ envKey, argName ] ) => {
if ( hasArgInCLI( argName ) ) {
process.env[ envKey ] = getArgFromCLI( argName );
}
} );
// Set the default artifacts path.
if ( ! process.env.WP_ARTIFACTS_PATH ) {
process.env.WP_ARTIFACTS_PATH = path.resolve(
process.env.GITHUB_WORKSPACE || process.cwd(),
'artifacts'
);
}
const cleanUpPrefixes = [ '--puppeteer-', '--wordpress-' ];
jest.run( [ ...config, ...runInBand, ...getArgsFromCLI( cleanUpPrefixes ) ] );

View File

@@ -0,0 +1,69 @@
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on( 'unhandledRejection', ( err ) => {
throw err;
} );
/**
* External dependencies
*/
const { resolve } = require( 'node:path' );
const { sync: spawn } = require( 'cross-spawn' );
/**
* Internal dependencies
*/
const {
fromConfigRoot,
hasProjectFile,
hasArgInCLI,
getArgsFromCLI,
getAsBooleanFromENV,
} = require( '../utils' );
if ( ! getAsBooleanFromENV( 'PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD' ) ) {
const result = spawn( 'npx', [ 'playwright', 'install' ], {
stdio: 'inherit',
} );
if ( result.status > 0 ) {
process.exit( result.status );
}
}
const config =
! hasArgInCLI( '--config' ) &&
! hasProjectFile( 'playwright.config.ts' ) &&
! hasProjectFile( 'playwright.config.js' )
? [ '--config', fromConfigRoot( 'playwright.config.js' ) ]
: [];
// Set the default artifacts path.
if ( ! process.env.WP_ARTIFACTS_PATH ) {
process.env.WP_ARTIFACTS_PATH = resolve(
process.env.GITHUB_WORKSPACE || process.cwd(),
'artifacts'
);
}
const testResult = spawn(
'node',
[
require.resolve( '@playwright/test/cli' ),
'test',
...config,
...getArgsFromCLI(),
],
{
stdio: 'inherit',
}
);
if ( testResult.status > 0 ) {
process.exit( testResult.status );
}

View File

@@ -0,0 +1,28 @@
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on( 'unhandledRejection', ( err ) => {
throw err;
} );
/**
* External dependencies
*/
const jest = require( 'jest' );
/**
* Internal dependencies
*/
const { getJestOverrideConfigFile, getArgsFromCLI } = require( '../utils' );
const configFile = getJestOverrideConfigFile( 'unit' );
const config = configFile
? [ '--config', JSON.stringify( require( configFile ) ) ]
: [];
jest.run( [ ...config, ...getArgsFromCLI() ] );

View File

@@ -0,0 +1 @@
require( './test-unit-jest' );

View File

@@ -0,0 +1,89 @@
/**
* External dependencies
*/
const fs = require( 'fs' );
const path = require( 'path' );
/**
* Internal dependencies
*/
import {
detectTypeFromLicenseText,
checkAllCompatible,
} from '../check-licenses';
describe( 'detectTypeFromLicenseText', () => {
let licenseText;
it( "should return 'Apache 2.0' when the license text is the Apache 2.0 license", () => {
licenseText = fs
.readFileSync( path.resolve( __dirname, 'licenses/apache2.txt' ) )
.toString();
expect( detectTypeFromLicenseText( licenseText ) ).toBe( 'Apache-2.0' );
} );
it( "should return 'BSD' when the license text is the BSD 3-clause license", () => {
licenseText = fs
.readFileSync(
path.resolve( __dirname, 'licenses/bsd3clause.txt' )
)
.toString();
expect( detectTypeFromLicenseText( licenseText ) ).toBe( 'BSD' );
} );
it( "should return 'BSD-3-Clause-W3C' when the license text is the W3C variation of the BSD 3-clause license", () => {
licenseText = fs
.readFileSync( path.resolve( __dirname, 'licenses/w3cbsd.txt' ) )
.toString();
expect( detectTypeFromLicenseText( licenseText ) ).toBe(
'BSD-3-Clause-W3C'
);
} );
it( "should return 'MIT' when the license text is the MIT license", () => {
licenseText = fs
.readFileSync( path.resolve( __dirname, 'licenses/mit.txt' ) )
.toString();
expect( detectTypeFromLicenseText( licenseText ) ).toBe( 'MIT' );
} );
it( "should return 'Apache2 AND MIT' when the license text is Apache2 followed by MIT license", () => {
licenseText = fs
.readFileSync(
path.resolve( __dirname, 'licenses/apache2-mit.txt' )
)
.toString();
expect( detectTypeFromLicenseText( licenseText ) ).toBe(
'Apache-2.0 AND MIT'
);
} );
} );
describe( 'checkAllCompatible', () => {
it( "should return 'true' when single license is in the allowed list", () => {
expect( checkAllCompatible( [ 'B' ], [ 'A', 'B', 'C' ] ) ).toBe( true );
} );
it( "should return 'false' when single license is not in the allowed list", () => {
expect( checkAllCompatible( [ 'D' ], [ 'A', 'B', 'C' ] ) ).toBe(
false
);
} );
it( "should return 'true' when all licenses are in the allowed list", () => {
expect( checkAllCompatible( [ 'A', 'C' ], [ 'A', 'B', 'C' ] ) ).toBe(
true
);
} );
it( "should return 'false' when any license is not in the allowed list", () => {
expect( checkAllCompatible( [ 'A', 'D' ], [ 'A', 'B', 'C' ] ) ).toBe(
false
);
} );
} );

View File

@@ -0,0 +1,227 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-----
Contains code from https://github.com/mozilla/language-mapping-list
The MIT License (MIT)
Copyright (c) 2013 fullname
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,28 @@
BSD 3-Clause License
Copyright (c) [year], [fullname]
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,7 @@
Copyright <YEAR> <COPYRIGHT HOLDER>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,9 @@
# W3C 3-clause BSD License
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of works must retain the original copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the original copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the W3C nor the names of its contributors may be used to endorse or promote products derived from this work without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

41
node_modules/@wordpress/scripts/utils/block-json.js generated vendored Normal file
View File

@@ -0,0 +1,41 @@
const moduleFields = new Set( [ 'viewScriptModule', 'viewModule' ] );
const scriptFields = new Set( [ 'viewScript', 'script', 'editorScript' ] );
/**
* @param {Object} blockJson
* @return {null|Record<string, unknown>} Fields
*/
function getBlockJsonModuleFields( blockJson ) {
let result = null;
for ( const field of moduleFields ) {
if ( Object.hasOwn( blockJson, field ) ) {
if ( ! result ) {
result = {};
}
result[ field ] = blockJson[ field ];
}
}
return result;
}
/**
* @param {Object} blockJson
* @return {null|Record<string, unknown>} Fields
*/
function getBlockJsonScriptFields( blockJson ) {
let result = null;
for ( const field of scriptFields ) {
if ( Object.hasOwn( blockJson, field ) ) {
if ( ! result ) {
result = {};
}
result[ field ] = blockJson[ field ];
}
}
return result;
}
module.exports = {
getBlockJsonModuleFields,
getBlockJsonScriptFields,
};

99
node_modules/@wordpress/scripts/utils/cli.js generated vendored Normal file
View File

@@ -0,0 +1,99 @@
/**
* External dependencies
*/
const minimist = require( 'minimist' );
const spawn = require( 'cross-spawn' );
/**
* Internal dependencies
*/
const { fromScriptsRoot, hasScriptFile, getScripts } = require( './file' );
const { exit, getArgsFromCLI } = require( './process' );
const getArgFromCLI = ( arg ) => {
for ( const cliArg of getArgsFromCLI() ) {
const [ name, value ] = cliArg.split( '=' );
if ( name === arg ) {
return value || null;
}
}
};
const hasArgInCLI = ( arg ) => getArgFromCLI( arg ) !== undefined;
const getFileArgsFromCLI = () => minimist( getArgsFromCLI() )._;
const getNodeArgsFromCLI = () => {
const args = getArgsFromCLI();
const scripts = getScripts();
const scriptIndex = args.findIndex( ( arg ) => scripts.includes( arg ) );
return {
nodeArgs: args.slice( 0, scriptIndex ),
scriptName: args[ scriptIndex ],
scriptArgs: args.slice( scriptIndex + 1 ),
};
};
const hasFileArgInCLI = () => getFileArgsFromCLI().length > 0;
const handleSignal = ( signal ) => {
if ( signal === 'SIGKILL' ) {
// eslint-disable-next-line no-console
console.log(
'The script failed because the process exited too early. ' +
'This probably means the system ran out of memory or someone called ' +
'`kill -9` on the process.'
);
} else if ( signal === 'SIGTERM' ) {
// eslint-disable-next-line no-console
console.log(
'The script failed because the process exited too early. ' +
'Someone might have called `kill` or `killall`, or the system could ' +
'be shutting down.'
);
}
exit( 1 );
};
const spawnScript = ( scriptName, args = [], nodeArgs = [] ) => {
if ( ! scriptName ) {
// eslint-disable-next-line no-console
console.log( 'Script name is missing.' );
exit( 1 );
}
if ( ! hasScriptFile( scriptName ) ) {
// eslint-disable-next-line no-console
console.log(
'Unknown script "' +
scriptName +
'". ' +
'Perhaps you need to update @wordpress/scripts?'
);
exit( 1 );
}
const { signal, status } = spawn.sync(
'node',
[ ...nodeArgs, fromScriptsRoot( scriptName ), ...args ],
{
stdio: 'inherit',
}
);
if ( signal ) {
handleSignal( signal );
}
exit( status );
};
module.exports = {
getArgFromCLI,
getArgsFromCLI,
getFileArgsFromCLI,
getNodeArgsFromCLI,
hasArgInCLI,
hasFileArgInCLI,
spawnScript,
};

413
node_modules/@wordpress/scripts/utils/config.js generated vendored Normal file
View File

@@ -0,0 +1,413 @@
/**
* External dependencies
*/
const chalk = require( 'chalk' );
const { readFileSync } = require( 'fs' );
const { basename, dirname, extname, join, sep } = require( 'path' );
const { sync: glob } = require( 'fast-glob' );
/**
* Internal dependencies
*/
const {
getArgsFromCLI,
getFileArgsFromCLI,
hasArgInCLI,
hasFileArgInCLI,
} = require( './cli' );
const { fromConfigRoot, fromProjectRoot, hasProjectFile } = require( './file' );
const { hasPackageProp } = require( './package' );
const {
getBlockJsonModuleFields,
getBlockJsonScriptFields,
} = require( './block-json' );
const { log } = console;
// See https://babeljs.io/docs/en/config-files#configuration-file-types.
const hasBabelConfig = () =>
hasProjectFile( '.babelrc.js' ) ||
hasProjectFile( '.babelrc.json' ) ||
hasProjectFile( 'babel.config.js' ) ||
hasProjectFile( 'babel.config.json' ) ||
hasProjectFile( '.babelrc' ) ||
hasPackageProp( 'babel' );
// See https://cssnano.co/docs/config-file.
const hasCssnanoConfig = () =>
hasProjectFile( '.cssnanorc' ) ||
hasProjectFile( '.cssnanorc.js' ) ||
hasProjectFile( '.cssnanorc.json' ) ||
hasProjectFile( '.cssnanorc.yaml' ) ||
hasProjectFile( '.cssnanorc.yml' ) ||
hasProjectFile( 'cssnano.config.js' ) ||
hasPackageProp( 'cssnano' );
/**
* Returns path to a Jest configuration which should be provided as the explicit
* configuration when there is none available for discovery by Jest in the
* project environment. Returns undefined if Jest should be allowed to discover
* an available configuration.
*
* This can be used in cases where multiple possible configurations are
* supported. Since Jest will only discover `jest.config.js`, or `jest` package
* directive, such custom configurations must be specified explicitly.
*
* @param {"e2e"|"unit"} suffix Suffix of configuration file to accept.
*
* @return {string= | undefined} Override or fallback configuration file path.
*/
function getJestOverrideConfigFile( suffix ) {
if ( hasArgInCLI( '-c' ) || hasArgInCLI( '--config' ) ) {
return;
}
if ( hasProjectFile( `jest-${ suffix }.config.js` ) ) {
return fromProjectRoot( `jest-${ suffix }.config.js` );
}
if ( ! hasJestConfig() ) {
return fromConfigRoot( `jest-${ suffix }.config.js` );
}
}
// See https://jestjs.io/docs/configuration.
const hasJestConfig = () =>
hasProjectFile( 'jest.config.js' ) ||
hasProjectFile( 'jest.config.json' ) ||
hasProjectFile( 'jest.config.ts' ) ||
hasPackageProp( 'jest' );
// See https://prettier.io/docs/en/configuration.html.
const hasPrettierConfig = () =>
hasProjectFile( '.prettierrc.js' ) ||
hasProjectFile( '.prettierrc.json' ) ||
hasProjectFile( '.prettierrc.toml' ) ||
hasProjectFile( '.prettierrc.yaml' ) ||
hasProjectFile( '.prettierrc.yml' ) ||
hasProjectFile( 'prettier.config.js' ) ||
hasProjectFile( '.prettierrc' ) ||
hasPackageProp( 'prettier' );
const hasWebpackConfig = () =>
hasArgInCLI( '--config' ) ||
hasProjectFile( 'webpack.config.js' ) ||
hasProjectFile( 'webpack.config.babel.js' );
// See https://github.com/michael-ciniawsky/postcss-load-config#usage (used by postcss-loader).
const hasPostCSSConfig = () =>
hasProjectFile( 'postcss.config.js' ) ||
hasProjectFile( '.postcssrc' ) ||
hasProjectFile( '.postcssrc.json' ) ||
hasProjectFile( '.postcssrc.yaml' ) ||
hasProjectFile( '.postcssrc.yml' ) ||
hasProjectFile( '.postcssrc.js' ) ||
hasPackageProp( 'postcss' );
/**
* Converts CLI arguments to the format which webpack understands.
*
* @see https://webpack.js.org/api/cli/#usage-with-config-file
*
* @return {Array} The list of CLI arguments to pass to webpack CLI.
*/
const getWebpackArgs = () => {
// Gets all args from CLI without those prefixed with `--webpack`.
let webpackArgs = getArgsFromCLI( [
'--experimental-modules',
'--webpack',
] );
const hasWebpackOutputOption =
hasArgInCLI( '-o' ) || hasArgInCLI( '--output' );
if (
! hasWebpackOutputOption &&
! hasArgInCLI( '--entry' ) &&
hasFileArgInCLI()
) {
/**
* Converts a legacy path to the entry pair supported by webpack, e.g.:
* `./entry-one.js` -> `[ 'entry-one', './entry-one.js] ]`
* `entry-two.js` -> `[ 'entry-two', './entry-two.js' ]`
*
* @param {string} path The path provided.
*
* @return {string[]} The entry pair of its name and the file path.
*/
const pathToEntry = ( path ) => {
const entryName = basename( path, '.js' );
if ( ! path.startsWith( './' ) ) {
path = './' + path;
}
return [ entryName, path ];
};
const fileArgs = getFileArgsFromCLI();
if ( fileArgs.length > 0 ) {
// Filters out all CLI arguments that are recognized as file paths.
const fileArgsToRemove = new Set( fileArgs );
webpackArgs = webpackArgs.filter( ( cliArg ) => {
if ( fileArgsToRemove.has( cliArg ) ) {
fileArgsToRemove.delete( cliArg );
return false;
}
return true;
} );
// Converts all CLI arguments that are file paths to the `entry` format supported by webpack.
// It is going to be consumed in the config through the WP_ENTRY global variable.
const entry = {};
fileArgs.forEach( ( fileArg ) => {
const [ entryName, path ] = fileArg.includes( '=' )
? fileArg.split( '=' )
: pathToEntry( fileArg );
entry[ entryName ] = path;
} );
process.env.WP_ENTRY = JSON.stringify( entry );
}
}
if ( ! hasWebpackConfig() ) {
webpackArgs.push( '--config', fromConfigRoot( 'webpack.config.js' ) );
}
return webpackArgs;
};
/**
* Returns the WordPress source directory. It defaults to 'src' if the
* `process.env.WP_SRC_DIRECTORY` variable is not set.
*
* @return {string} The WordPress source directory.
*/
function getWordPressSrcDirectory() {
return process.env.WP_SRC_DIRECTORY || 'src';
}
/**
* Detects the list of entry points to use with webpack. There are three ways to do this:
* 1. Use the legacy webpack 4 format passed as CLI arguments.
* 2. Scan `block.json` files for scripts.
* 3. Fallback to `src/index.*` file.
*
* @see https://webpack.js.org/concepts/entry-points/
*
* @param {'script' | 'module'} buildType
*/
function getWebpackEntryPoints( buildType ) {
/**
* @return {Object<string,string>} The list of entry points.
*/
return () => {
// 1. Handles the legacy format for entry points when explicitly provided with the `process.env.WP_ENTRY`.
if ( process.env.WP_ENTRY ) {
return buildType === 'script'
? JSON.parse( process.env.WP_ENTRY )
: {};
}
// Continue only if the source directory exists.
if ( ! hasProjectFile( getWordPressSrcDirectory() ) ) {
log(
chalk.yellow(
`Source directory "${ getWordPressSrcDirectory() }" was not found. Please confirm there is a "src" directory in the root or the value passed to --webpack-src-dir is correct.`
)
);
return {};
}
// 2. Checks whether any block metadata files can be detected in the defined source directory.
// It scans all discovered files looking for JavaScript assets and converts them to entry points.
const blockMetadataFiles = glob( '**/block.json', {
absolute: true,
cwd: fromProjectRoot( getWordPressSrcDirectory() ),
} );
if ( blockMetadataFiles.length > 0 ) {
const srcDirectory = fromProjectRoot(
getWordPressSrcDirectory() + sep
);
const entryPoints = {};
for ( const blockMetadataFile of blockMetadataFiles ) {
const fileContents = readFileSync( blockMetadataFile );
let parsedBlockJson;
// wrapping in try/catch in case the file is malformed
// this happens especially when new block.json files are added
// at which point they are completely empty and therefore not valid JSON
try {
parsedBlockJson = JSON.parse( fileContents );
} catch ( error ) {
chalk.yellow(
`Skipping "${ blockMetadataFile.replace(
fromProjectRoot( sep ),
''
) }" due to malformed JSON.`
);
}
const fields =
buildType === 'script'
? getBlockJsonScriptFields( parsedBlockJson )
: getBlockJsonModuleFields( parsedBlockJson );
if ( ! fields ) {
continue;
}
for ( const value of Object.values( fields ).flat() ) {
if ( ! value.startsWith( 'file:' ) ) {
continue;
}
// Removes the `file:` prefix.
const filepath = join(
dirname( blockMetadataFile ),
value.replace( 'file:', '' )
);
// Takes the path without the file extension, and relative to the defined source directory.
if ( ! filepath.startsWith( srcDirectory ) ) {
log(
chalk.yellow(
`Skipping "${ value.replace(
'file:',
''
) }" listed in "${ blockMetadataFile.replace(
fromProjectRoot( sep ),
''
) }". File is located outside of the "${ getWordPressSrcDirectory() }" directory.`
)
);
return;
}
const entryName = filepath
.replace( extname( filepath ), '' )
.replace( srcDirectory, '' )
.replace( /\\/g, '/' );
// Detects the proper file extension used in the defined source directory.
const [ entryFilepath ] = glob(
`${ entryName }.?(m)[jt]s?(x)`,
{
absolute: true,
cwd: fromProjectRoot( getWordPressSrcDirectory() ),
}
);
if ( ! entryFilepath ) {
log(
chalk.yellow(
`Skipping "${ value.replace(
'file:',
''
) }" listed in "${ blockMetadataFile.replace(
fromProjectRoot( sep ),
''
) }". File does not exist in the "${ getWordPressSrcDirectory() }" directory.`
)
);
return;
}
entryPoints[ entryName ] = entryFilepath;
}
}
if ( Object.keys( entryPoints ).length > 0 ) {
return entryPoints;
}
}
// Don't do any further processing if this is a module build.
// This only respects *module block.json fields.
if ( buildType === 'module' ) {
return {};
}
// 3. Checks whether a standard file name can be detected in the defined source directory,
// and converts the discovered file to entry point.
const [ entryFile ] = glob( 'index.[jt]s?(x)', {
absolute: true,
cwd: fromProjectRoot( getWordPressSrcDirectory() ),
} );
if ( ! entryFile ) {
log(
chalk.yellow(
`No entry file discovered in the "${ getWordPressSrcDirectory() }" directory.`
)
);
return {};
}
return {
index: entryFile,
};
};
}
/**
* Returns the list of paths included in the `render` props by scanning the `block.json` files.
*
* @return {Array} The list of all the `render` prop paths included in `block.json` files.
*/
function getRenderPropPaths() {
// Continue only if the source directory exists.
if ( ! hasProjectFile( getWordPressSrcDirectory() ) ) {
return [];
}
// Checks whether any block metadata files can be detected in the defined source directory.
const blockMetadataFiles = glob( '**/block.json', {
absolute: true,
cwd: fromProjectRoot( getWordPressSrcDirectory() ),
} );
const srcDirectory = fromProjectRoot( getWordPressSrcDirectory() + sep );
const renderPaths = blockMetadataFiles.map( ( blockMetadataFile ) => {
const { render } = JSON.parse( readFileSync( blockMetadataFile ) );
if ( render && render.startsWith( 'file:' ) ) {
// Removes the `file:` prefix.
const filepath = join(
dirname( blockMetadataFile ),
render.replace( 'file:', '' )
);
// Takes the path without the file extension, and relative to the defined source directory.
if ( ! filepath.startsWith( srcDirectory ) ) {
log(
chalk.yellow(
`Skipping "${ render.replace(
'file:',
''
) }" listed in "${ blockMetadataFile.replace(
fromProjectRoot( sep ),
''
) }". File is located outside of the "${ getWordPressSrcDirectory() }" directory.`
)
);
return false;
}
return filepath.replace( /\\/g, '/' );
}
return false;
} );
return renderPaths.filter( ( renderPath ) => renderPath );
}
module.exports = {
getJestOverrideConfigFile,
getWebpackArgs,
getWordPressSrcDirectory,
getWebpackEntryPoints,
getRenderPropPaths,
hasBabelConfig,
hasCssnanoConfig,
hasJestConfig,
hasPostCSSConfig,
hasPrettierConfig,
};

39
node_modules/@wordpress/scripts/utils/file.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
/**
* External dependencies
*/
const { existsSync, readdirSync } = require( 'fs' );
const path = require( 'path' );
/**
* Internal dependencies
*/
const { getPackagePath } = require( './package' );
const fromProjectRoot = ( fileName ) =>
path.join( path.dirname( getPackagePath() ), fileName );
const hasProjectFile = ( fileName ) =>
existsSync( fromProjectRoot( fileName ) );
const fromConfigRoot = ( fileName ) =>
path.join( path.dirname( __dirname ), 'config', fileName );
const fromScriptsRoot = ( scriptName ) =>
path.join( path.dirname( __dirname ), 'scripts', `${ scriptName }.js` );
const hasScriptFile = ( scriptName ) =>
existsSync( fromScriptsRoot( scriptName ) );
const getScripts = () =>
readdirSync( path.join( path.dirname( __dirname ), 'scripts' ) )
.filter( ( f ) => path.extname( f ) === '.js' )
.map( ( f ) => path.basename( f, '.js' ) );
module.exports = {
fromProjectRoot,
fromConfigRoot,
fromScriptsRoot,
getScripts,
hasProjectFile,
hasScriptFile,
};

59
node_modules/@wordpress/scripts/utils/index.js generated vendored Normal file
View File

@@ -0,0 +1,59 @@
/**
* Internal dependencies
*/
const { getAsBooleanFromENV } = require( './process' );
const {
getArgFromCLI,
getArgsFromCLI,
getFileArgsFromCLI,
getNodeArgsFromCLI,
hasArgInCLI,
hasFileArgInCLI,
spawnScript,
} = require( './cli' );
const {
getJestOverrideConfigFile,
getWebpackArgs,
getWordPressSrcDirectory,
getWebpackEntryPoints,
getRenderPropPaths,
hasBabelConfig,
hasCssnanoConfig,
hasJestConfig,
hasPostCSSConfig,
hasPrettierConfig,
} = require( './config' );
const { fromProjectRoot, fromConfigRoot, hasProjectFile } = require( './file' );
const { getPackageProp, hasPackageProp } = require( './package' );
const {
getBlockJsonModuleFields,
getBlockJsonScriptFields,
} = require( './block-json' );
module.exports = {
fromProjectRoot,
fromConfigRoot,
getAsBooleanFromENV,
getArgFromCLI,
getArgsFromCLI,
getFileArgsFromCLI,
getJestOverrideConfigFile,
getNodeArgsFromCLI,
getPackageProp,
getWebpackArgs,
getWordPressSrcDirectory,
getWebpackEntryPoints,
getRenderPropPaths,
getBlockJsonModuleFields,
getBlockJsonScriptFields,
hasArgInCLI,
hasBabelConfig,
hasCssnanoConfig,
hasFileArgInCLI,
hasJestConfig,
hasPackageProp,
hasPostCSSConfig,
hasPrettierConfig,
hasProjectFile,
spawnScript,
};

27
node_modules/@wordpress/scripts/utils/package.js generated vendored Normal file
View File

@@ -0,0 +1,27 @@
/**
* External dependencies
*/
const { realpathSync } = require( 'fs' );
const { sync: readPkgUp } = require( 'read-pkg-up' );
/**
* Internal dependencies
*/
const { getCurrentWorkingDirectory } = require( './process' );
const { packageJson, path: pkgPath } = readPkgUp( {
cwd: realpathSync( getCurrentWorkingDirectory() ),
} );
const getPackagePath = () => pkgPath;
const getPackageProp = ( prop ) => packageJson && packageJson[ prop ];
const hasPackageProp = ( prop ) =>
packageJson && packageJson.hasOwnProperty( prop );
module.exports = {
getPackagePath,
getPackageProp,
hasPackageProp,
};

23
node_modules/@wordpress/scripts/utils/process.js generated vendored Normal file
View File

@@ -0,0 +1,23 @@
const getAsBooleanFromENV = ( name ) => {
const value = process.env[ name ];
return !! value && value !== 'false' && value !== '0';
};
const getArgsFromCLI = ( excludePrefixes ) => {
const args = process.argv.slice( 2 );
if ( excludePrefixes ) {
return args.filter( ( arg ) => {
return ! excludePrefixes.some( ( prefix ) =>
arg.startsWith( prefix )
);
} );
}
return args;
};
module.exports = {
exit: process.exit,
getAsBooleanFromENV,
getArgsFromCLI,
getCurrentWorkingDirectory: process.cwd,
};

274
node_modules/@wordpress/scripts/utils/test/index.js generated vendored Normal file
View File

@@ -0,0 +1,274 @@
/**
* External dependencies
*/
import crossSpawn from 'cross-spawn';
/**
* Internal dependencies
*/
import {
hasArgInCLI,
hasProjectFile,
getJestOverrideConfigFile,
spawnScript,
} from '../';
import {
getPackagePath as getPackagePathMock,
hasPackageProp as hasPackagePropMock,
} from '../package';
import {
exit as exitMock,
getArgsFromCLI as getArgsFromCLIMock,
} from '../process';
import {
hasProjectFile as hasProjectFileMock,
fromProjectRoot as fromProjectRootMock,
fromConfigRoot as fromConfigRootMock,
} from '../file';
jest.mock( '../package', () => {
const module = jest.requireActual( '../package' );
jest.spyOn( module, 'getPackagePath' );
jest.spyOn( module, 'hasPackageProp' );
return module;
} );
jest.mock( '../process', () => {
const module = jest.requireActual( '../process' );
jest.spyOn( module, 'exit' );
jest.spyOn( module, 'getArgsFromCLI' );
return module;
} );
jest.mock( '../file', () => {
const module = jest.requireActual( '../file' );
jest.spyOn( module, 'hasProjectFile' );
jest.spyOn( module, 'fromProjectRoot' );
jest.spyOn( module, 'fromConfigRoot' );
return module;
} );
describe( 'utils', () => {
const crossSpawnMock = jest.spyOn( crossSpawn, 'sync' );
describe( 'hasArgInCLI', () => {
beforeAll( () => {
getArgsFromCLIMock.mockReturnValue( [
'-a',
'--b',
'--config=test',
] );
} );
afterAll( () => {
getArgsFromCLIMock.mockReset();
} );
test( 'should return false when no args passed', () => {
getArgsFromCLIMock.mockReturnValueOnce( [] );
expect( hasArgInCLI( '--no-args' ) ).toBe( false );
} );
test( 'should return false when checking for unrecognized arg', () => {
expect( hasArgInCLI( '--non-existent' ) ).toBe( false );
} );
test( 'should return true when CLI arg found', () => {
expect( hasArgInCLI( '-a' ) ).toBe( true );
expect( hasArgInCLI( '--b' ) ).toBe( true );
expect( hasArgInCLI( '--config' ) ).toBe( true );
} );
} );
describe( 'hasProjectFile', () => {
test( 'should return false for the current directory and unknown file', () => {
getPackagePathMock.mockReturnValueOnce( __dirname );
expect( hasProjectFile( 'unknown-file.name' ) ).toBe( false );
} );
test( 'should return true for the current directory and this file', () => {
getPackagePathMock.mockReturnValueOnce( __dirname );
expect( hasProjectFile( 'index.js' ) ).toBe( true );
} );
} );
describe( 'getJestOverrideConfigFile', () => {
beforeEach( () => {
getArgsFromCLIMock.mockReturnValue( [] );
hasPackagePropMock.mockReturnValue( false );
hasProjectFileMock.mockReturnValue( false );
fromProjectRootMock.mockImplementation( ( path ) => '/p/' + path );
fromConfigRootMock.mockImplementation( ( path ) => '/c/' + path );
} );
afterEach( () => {
getArgsFromCLIMock.mockReset();
hasPackagePropMock.mockReset();
hasProjectFileMock.mockReset();
fromProjectRootMock.mockReset();
fromConfigRootMock.mockReset();
} );
it( 'should return undefined if --config flag is present', () => {
getArgsFromCLIMock.mockReturnValue( [ '--config=test' ] );
expect( getJestOverrideConfigFile( 'e2e' ) ).toBe( undefined );
} );
it( 'should return undefined if -c flag is present', () => {
getArgsFromCLIMock.mockReturnValue( [ '-c=test' ] );
expect( getJestOverrideConfigFile( 'e2e' ) ).toBe( undefined );
} );
it( 'should return variant project configuration if present', () => {
hasProjectFileMock.mockImplementation(
( file ) => file === 'jest-e2e.config.js'
);
expect( getJestOverrideConfigFile( 'e2e' ) ).toBe(
'/p/jest-e2e.config.js'
);
} );
it( 'should return undefined if jest.config.js available', () => {
hasProjectFileMock.mockImplementation(
( file ) => file === 'jest.config.js'
);
expect( getJestOverrideConfigFile( 'e2e' ) ).toBe( undefined );
} );
it( 'should return undefined if jest.config.json available', () => {
hasProjectFileMock.mockImplementation(
( file ) => file === 'jest.config.json'
);
expect( getJestOverrideConfigFile( 'e2e' ) ).toBe( undefined );
} );
it( 'should return undefined if jest package directive specified', () => {
hasPackagePropMock.mockImplementation(
( prop ) => prop === 'jest'
);
expect( getJestOverrideConfigFile( 'e2e' ) ).toBe( undefined );
} );
it( 'should return default configuration if nothing available', () => {
expect( getJestOverrideConfigFile( 'e2e' ) ).toBe(
'/c/jest-e2e.config.js'
);
expect( getJestOverrideConfigFile( 'unit' ) ).toBe(
'/c/jest-unit.config.js'
);
} );
} );
describe( 'spawnScript', () => {
const scriptName = 'test-unit-js';
beforeAll( () => {
exitMock.mockImplementation( ( code ) => {
throw new Error( `Exit code: ${ code }.` );
} );
} );
afterAll( () => {
exitMock.mockReset();
} );
test( 'should exit when no script name provided', () => {
expect( () => spawnScript() ).toThrow( 'Exit code: 1.' );
expect( console ).toHaveLoggedWith( 'Script name is missing.' );
} );
test( 'should exit when an unknown script name provided', () => {
expect( () => spawnScript( 'unknown-script' ) ).toThrow(
'Exit code: 1.'
);
expect( console ).toHaveLoggedWith(
'Unknown script "unknown-script". Perhaps you need to update @wordpress/scripts?'
);
} );
test( 'should exit when the script failed because of SIGKILL signal', () => {
crossSpawnMock.mockReturnValueOnce( { signal: 'SIGKILL' } );
expect( () => spawnScript( scriptName ) ).toThrow(
'Exit code: 1.'
);
expect( console ).toHaveLogged();
} );
test( 'should exit when the script failed because of SIGTERM signal', () => {
crossSpawnMock.mockReturnValueOnce( { signal: 'SIGTERM' } );
expect( () => spawnScript( scriptName ) ).toThrow(
'Exit code: 1.'
);
expect( console ).toHaveLogged();
} );
test( 'should pass inspect args to node', () => {
crossSpawnMock.mockReturnValueOnce( { status: 0 } );
expect( () =>
spawnScript( scriptName, [], [ '--inspect-brk' ] )
).toThrow( 'Exit code: 0.' );
expect( crossSpawnMock ).toHaveBeenCalledWith(
'node',
[ '--inspect-brk', expect.stringContaining( scriptName ) ],
{ stdio: 'inherit' }
);
} );
test( 'should pass script args to the script', () => {
crossSpawnMock.mockReturnValueOnce( { status: 0 } );
expect( () =>
spawnScript( scriptName, [ '--runInBand' ] )
).toThrow( 'Exit code: 0.' );
expect( crossSpawnMock ).toHaveBeenCalledWith(
'node',
[ expect.stringContaining( scriptName ), '--runInBand' ],
{ stdio: 'inherit' }
);
} );
test( 'should finish successfully when the script properly executed', () => {
crossSpawnMock.mockReturnValueOnce( { status: 0 } );
expect( () => spawnScript( scriptName ) ).toThrow(
'Exit code: 0.'
);
expect( crossSpawnMock ).toHaveBeenCalledWith(
'node',
[ expect.stringContaining( scriptName ) ],
{ stdio: 'inherit' }
);
} );
test( 'should finish successfully when the script properly executed with args', () => {
crossSpawnMock.mockReturnValueOnce( { status: 0 } );
const args = [ '-a', '--bbb', '-c=ccccc' ];
expect( () => spawnScript( scriptName, args ) ).toThrow(
'Exit code: 0.'
);
expect( crossSpawnMock ).toHaveBeenCalledWith(
'node',
[ expect.stringContaining( scriptName ), ...args ],
{ stdio: 'inherit' }
);
} );
} );
} );