mirror of
https://github.com/danog/phpdoc.git
synced 2024-11-26 12:04:47 +01:00
First commit
This commit is contained in:
commit
864295ff3f
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
composer.lock
|
||||
vendor
|
||||
.php_cs.cache
|
14
.php_cs.dist
Normal file
14
.php_cs.dist
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
$config = new Amp\CodeStyle\Config();
|
||||
$config->getFinder()
|
||||
->in(__DIR__ . '/src');
|
||||
//->in(__DIR__ . '/tests')
|
||||
//->in(__DIR__ . '/examples')
|
||||
//->in(__DIR__ . '/tools');
|
||||
|
||||
$cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__;
|
||||
|
||||
$config->setCacheFile($cacheDir . '/.php_cs.cache');
|
||||
|
||||
return $config;
|
661
LICENSE
Normal file
661
LICENSE
Normal file
@ -0,0 +1,661 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
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
|
||||
them 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.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero 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 that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
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
|
||||
state 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 a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
17
bin/phpdoc
Executable file
17
bin/phpdoc
Executable file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use danog\PhpDoc\PhpDocBuilder;
|
||||
|
||||
if ($argc < 2) {
|
||||
$me = $argv[0];
|
||||
fprintf(stderr, "Usage: $me filePath [namespace]\n");
|
||||
die(1);
|
||||
}
|
||||
|
||||
$path = $argv[1];
|
||||
$namespace = $argv[2] ?? '';
|
||||
|
||||
PhpDocBuilder::fromNamespace($namespace)
|
||||
->setOutput($path)
|
||||
->run();
|
40
composer.json
Normal file
40
composer.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "danog/phpdoc",
|
||||
"description": "Simple markdown PHPDOC documentation generator with psalm type annotation support.",
|
||||
"type": "project",
|
||||
"license": "AGPL-3.0-only",
|
||||
"homepage": "https://phpdoc.daniil.it",
|
||||
"keywords": ["phpdoc", "markdown", "documentation", "psalm"],
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"danog/class-finder": "dev-master",
|
||||
"phpdocumentor/reflection-docblock": "^5.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"vimeo/psalm": "dev-master",
|
||||
"amphp/php-cs-fixer-config": "dev-master",
|
||||
"friendsofphp/php-cs-fixer": "^2"
|
||||
},
|
||||
"authors": [{
|
||||
"name": "Daniil Gentili",
|
||||
"email": "daniil@daniil.it"
|
||||
}],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"danog\\PhpDoc\\": "src/"
|
||||
}
|
||||
},
|
||||
"bin": [
|
||||
"bin/phpdoc"
|
||||
],
|
||||
"scripts": {
|
||||
"check": [
|
||||
"@cs",
|
||||
"@test"
|
||||
],
|
||||
"cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff --dry-run",
|
||||
"cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff",
|
||||
"psalm": "psalm",
|
||||
"docs": "php tools/build_docs.php"
|
||||
}
|
||||
}
|
138
src/PhpDoc/ClassDoc.php
Normal file
138
src/PhpDoc/ClassDoc.php
Normal file
@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace danog\PhpDoc\PhpDoc;
|
||||
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Property;
|
||||
use ReflectionClass;
|
||||
use ReflectionClassConstant;
|
||||
use ReflectionMethod;
|
||||
|
||||
class ClassDoc extends GenericDoc
|
||||
{
|
||||
/**
|
||||
* Properties.
|
||||
*
|
||||
* @var array<string, array>
|
||||
*/
|
||||
private array $properties = [];
|
||||
/**
|
||||
* Methods.
|
||||
*
|
||||
* @var array<string, MethodDoc>
|
||||
*/
|
||||
private array $methods = [];
|
||||
/**
|
||||
* Constants.
|
||||
*/
|
||||
private array $constants = [];
|
||||
public function __construct(PhpDoc $builder, ReflectionClass $reflectionClass)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->name = $reflectionClass->getName();
|
||||
$doc = $reflectionClass->getDocComment();
|
||||
if (!$doc) {
|
||||
\fprintf(STDERR, $reflectionClass->getName()." has no PHPDOC\n");
|
||||
$this->ignore = true;
|
||||
return;
|
||||
}
|
||||
$doc = $this->builder->getFactory()->create($doc);
|
||||
|
||||
parent::__construct($doc, $reflectionClass);
|
||||
|
||||
$tags = $doc->getTags();
|
||||
foreach ($tags as $tag) {
|
||||
if ($tag instanceof Property) {
|
||||
$this->properties[$tag->getVariableName()] = [
|
||||
$tag->getType(),
|
||||
$tag->getDescription()
|
||||
];
|
||||
}
|
||||
if ($tag instanceof InvalidTag && $tag->getName() === 'property') {
|
||||
[$type, $description] = \explode(" $", $tag->render(), 2);
|
||||
$description .= ' ';
|
||||
[$varName, $description] = \explode(" ", $description, 2);
|
||||
$type = \str_replace('@property ', '', $type);
|
||||
$description ??= '';
|
||||
$this->properties[$varName] = [
|
||||
$type,
|
||||
$description
|
||||
];
|
||||
}
|
||||
}
|
||||
foreach ($reflectionClass->getConstants() as $key => $value) {
|
||||
$refl = new ReflectionClassConstant($reflectionClass->getName(), $key);
|
||||
if (!$refl->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
$description = '';
|
||||
if ($refl->getDocComment()) {
|
||||
$docConst = $this->builder->getFactory()->create($refl->getDocComment());
|
||||
if ($this->builder->shouldIgnore($refl->getDeclaringClass()->getName())) {
|
||||
continue;
|
||||
}
|
||||
foreach ($docConst->getTags() as $tag) {
|
||||
if ($tag instanceof Generic && $tag->getName() === 'internal') {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
$description .= $docConst->getSummary();
|
||||
if ($docConst->getDescription()) {
|
||||
$description .= "\n\n";
|
||||
$description .= $docConst->getDescription();
|
||||
}
|
||||
}
|
||||
$description = \trim($description);
|
||||
$this->constants[$key] = [
|
||||
$value,
|
||||
$description
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
|
||||
if (str_starts_with($method->getName(), '__') && $method !== '__construct') {
|
||||
continue;
|
||||
}
|
||||
$this->methods[$method->getName()] = new MethodDoc($this->builder, $method);
|
||||
}
|
||||
|
||||
$this->methods = \array_filter($this->methods, fn (MethodDoc $doc): bool => !$doc->shouldIgnore());
|
||||
}
|
||||
|
||||
public function format(): string
|
||||
{
|
||||
$init = parent::format();
|
||||
if ($this->constants) {
|
||||
$init .= "\n";
|
||||
$init .= "## Constants\n";
|
||||
foreach ($this->constants as $name => [, $description]) {
|
||||
$description = \trim($description);
|
||||
$description = \str_replace("\n", "\n ", $description);
|
||||
$init .= "* {$this->className}::$name: $description\n";
|
||||
$init .= "\n";
|
||||
}
|
||||
}
|
||||
if ($this->methods) {
|
||||
$init .= "\n";
|
||||
$init .= "## Method list:\n";
|
||||
foreach ($this->methods as $method) {
|
||||
$init .= "* `".$method->getSignature()."`\n";
|
||||
}
|
||||
$init .= "\n";
|
||||
$init .= "## Methods:\n";
|
||||
foreach ($this->methods as $method) {
|
||||
$init .= $method->format();
|
||||
$init .= "\n";
|
||||
}
|
||||
}
|
||||
if ($this->properties) {
|
||||
$init .= "## Properties\n";
|
||||
foreach ($this->properties as $name => [$type, $description]) {
|
||||
$init .= "* `\$$name`: `$type` $description";
|
||||
}
|
||||
}
|
||||
return $init;
|
||||
}
|
||||
}
|
23
src/PhpDoc/FunctionDoc.php
Normal file
23
src/PhpDoc/FunctionDoc.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace danog\PhpDoc\PhpDoc;
|
||||
|
||||
use ReflectionFunction;
|
||||
|
||||
class FunctionDoc extends MethodDoc
|
||||
{
|
||||
public function __construct(PhpDoc $builder, ReflectionFunction $reflectionClass)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->nameGenericDoc = $reflectionClass->getName();
|
||||
$doc = $reflectionClass->getDocComment();
|
||||
if (!$doc) {
|
||||
\fprintf(STDERR, $reflectionClass->getName()." has no PHPDOC\n");
|
||||
$this->ignore = true;
|
||||
return;
|
||||
}
|
||||
$doc = $this->builder->getFactory()->create($doc);
|
||||
|
||||
parent::__construct($builder, $reflectionClass);
|
||||
}
|
||||
}
|
233
src/PhpDoc/GenericDoc.php
Normal file
233
src/PhpDoc/GenericDoc.php
Normal file
@ -0,0 +1,233 @@
|
||||
<?php
|
||||
|
||||
namespace danog\PhpDoc\PhpDoc;
|
||||
|
||||
use danog\PhpDoc\PhpDocBuilder;
|
||||
use phpDocumentor\Reflection\DocBlock;
|
||||
use phpDocumentor\Reflection\DocBlock\Description;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Author;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Deprecated;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Fqsen;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Url;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\See;
|
||||
use phpDocumentor\Reflection\Fqsen as ReflectionFqsen;
|
||||
|
||||
abstract class GenericDoc
|
||||
{
|
||||
/**
|
||||
* Builder instance.
|
||||
*/
|
||||
protected PhpDoc $builder;
|
||||
/**
|
||||
* Name.
|
||||
*/
|
||||
protected string $name;
|
||||
/**
|
||||
* Title.
|
||||
*/
|
||||
protected string $title;
|
||||
/**
|
||||
* Description.
|
||||
*/
|
||||
protected Description $description;
|
||||
/**
|
||||
* See also array.
|
||||
*
|
||||
* @var array<string, See>
|
||||
*/
|
||||
protected array $seeAlso = [];
|
||||
/**
|
||||
* Authors.
|
||||
*
|
||||
* @var Author[]
|
||||
*/
|
||||
protected array $authors;
|
||||
/**
|
||||
* Ignore this class.
|
||||
*/
|
||||
protected bool $ignore = false;
|
||||
/**
|
||||
* Class name.
|
||||
*/
|
||||
protected string $className;
|
||||
/**
|
||||
* Class namespace.
|
||||
*/
|
||||
protected string $namespace;
|
||||
/**
|
||||
* Fully qualified class name.
|
||||
*/
|
||||
private string $resolvedClassName;
|
||||
public function __construct(DocBlock $doc, $reflectionClass)
|
||||
{
|
||||
$empty = [];
|
||||
$this->className = $reflectionClass->getName();
|
||||
$this->resolvedClassName = $this->builder->resolveTypeAlias($this->className, $this->className, $empty);
|
||||
$this->namespace = \str_replace('/', '\\', \dirname(\str_replace('\\', '/', $this->className)));
|
||||
$this->title = $doc->getSummary();
|
||||
$this->description = $doc->getDescription();
|
||||
$tags = $doc->getTags();
|
||||
|
||||
$this->authors = $this->builder->getAuthors();
|
||||
foreach ($tags as $tag) {
|
||||
if ($tag instanceof Author) {
|
||||
$this->authors []= $tag;
|
||||
}
|
||||
if ($tag instanceof Deprecated) {
|
||||
$this->ignore = true;
|
||||
break;
|
||||
}
|
||||
if ($tag instanceof Generic && $tag->getName() === 'internal') {
|
||||
$this->ignore = true;
|
||||
break;
|
||||
}
|
||||
if ($tag instanceof See) {
|
||||
$this->seeAlso[$tag->getReference()->__toString()] = $tag;
|
||||
}
|
||||
}
|
||||
$this->authors = \array_unique($this->authors);
|
||||
}
|
||||
|
||||
public function seeAlso(): string
|
||||
{
|
||||
$empty = [];
|
||||
$seeAlso = '';
|
||||
foreach ($this->seeAlso as $see) {
|
||||
$ref = $see->getReference();
|
||||
if ($ref instanceof Fqsen) {
|
||||
$ref = (string) $ref;
|
||||
$ref = $this->builder->resolveTypeAlias($this->className, $ref, $empty);
|
||||
|
||||
$to = \explode("\\", $ref.".md");
|
||||
if (\count($to) === 2 || !$this->builder->hasClass($ref)) {
|
||||
$seeAlso .= "* `$ref`\n";
|
||||
continue;
|
||||
}
|
||||
$from = \explode('\\', $this->resolvedClassName);
|
||||
|
||||
$relPath = $to;
|
||||
foreach ($from as $depth => $dir) {
|
||||
// find first non-matching dir
|
||||
if ($dir === $to[$depth]) {
|
||||
// ignore this directory
|
||||
\array_shift($relPath);
|
||||
} else {
|
||||
// get number of remaining dirs to $from
|
||||
$remaining = \count($from) - $depth;
|
||||
if ($remaining > 1) {
|
||||
// add traversals up to first matching dir
|
||||
$padLength = (\count($relPath) + $remaining - 1) * -1;
|
||||
$relPath = \array_pad($relPath, $padLength, '..');
|
||||
break;
|
||||
}
|
||||
$relPath[0] = './'.$relPath[0];
|
||||
}
|
||||
}
|
||||
$path = \implode('/', $relPath);
|
||||
|
||||
if (!$desc = $see->getDescription()) {
|
||||
if ($desc = $this->builder->getTitle($ref)) {
|
||||
$desc = "`$ref`: $desc";
|
||||
} else {
|
||||
$desc = $ref;
|
||||
}
|
||||
}
|
||||
$seeAlso .= "* [$desc]($path)\n";
|
||||
}
|
||||
if ($ref instanceof Url) {
|
||||
$desc = $see->getDescription() ?: $ref;
|
||||
$seeAlso .= "* [$desc]($ref)\n";
|
||||
}
|
||||
}
|
||||
if ($seeAlso) {
|
||||
$seeAlso = "\n#### See also: \n$seeAlso\n\n";
|
||||
}
|
||||
return $seeAlso;
|
||||
}
|
||||
public function format(): string
|
||||
{
|
||||
$authors = '';
|
||||
foreach ($this->authors as $author) {
|
||||
$authors .= "> Author: $author \n";
|
||||
}
|
||||
$seeAlso = $this->seeAlso();
|
||||
$image = $this->builder->getImage();
|
||||
$index = '';
|
||||
$count = count(explode('\\', $this->resolvedClassName)) - 1;
|
||||
$index .= str_repeat($count, '../');
|
||||
$index .= 'index.md';
|
||||
return <<<EOF
|
||||
---
|
||||
title: $this->name: $this->title
|
||||
description: $this->description
|
||||
$image
|
||||
---
|
||||
# `$this->name`
|
||||
[Back to index]($index)
|
||||
|
||||
$authors
|
||||
|
||||
$this->title
|
||||
|
||||
$this->description
|
||||
$seeAlso
|
||||
EOF;
|
||||
}
|
||||
public function resolveTypeAlias(string $o): string
|
||||
{
|
||||
$resolved = [];
|
||||
$result = $this->builder->resolveTypeAlias($this->className, $o, $resolved);
|
||||
foreach ($resolved as $type) {
|
||||
if (PhpDoc::isScalar($type)) {
|
||||
continue;
|
||||
}
|
||||
if ($type === $this->resolvedClassName) {
|
||||
continue;
|
||||
}
|
||||
if (str_contains($type, ' ')) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$this->seeAlso[$type] = new See(new Fqsen(new ReflectionFqsen($type)));
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function shouldIgnore(): bool
|
||||
{
|
||||
return $this->ignore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get title.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fully qualified class name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getResolvedClassName(): string
|
||||
{
|
||||
return $this->resolvedClassName;
|
||||
}
|
||||
}
|
128
src/PhpDoc/MethodDoc.php
Normal file
128
src/PhpDoc/MethodDoc.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace danog\PhpDoc\PhpDoc;
|
||||
|
||||
use phpDocumentor\Reflection\DocBlock\Description;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Param;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
|
||||
use ReflectionFunctionAbstract;
|
||||
use ReflectionMethod;
|
||||
|
||||
class MethodDoc extends GenericDoc
|
||||
{
|
||||
private Return_ $return;
|
||||
private string $psalmReturn;
|
||||
private array $params = [];
|
||||
private array $psalmParams = [];
|
||||
public function __construct(PhpDoc $phpDocBuilder, ReflectionFunctionAbstract $method)
|
||||
{
|
||||
$this->builder = $phpDocBuilder;
|
||||
$this->name = $method->getName();
|
||||
$doc = $method->getDocComment();
|
||||
if (!$doc) {
|
||||
$this->ignore = true;
|
||||
if ($method instanceof ReflectionMethod) {
|
||||
\fprintf(STDERR, $method->getDeclaringClass()->getName().'::'.$method->getName().' has no PHPDOC!\n');
|
||||
} else {
|
||||
\fprintf(STDERR, $method->getName().' has no PHPDOC!\n');
|
||||
}
|
||||
return;
|
||||
}
|
||||
$doc = $this->builder->getFactory()->create($doc);
|
||||
|
||||
parent::__construct($doc, $method instanceof ReflectionMethod ? $method->getDeclaringClass() : $method);
|
||||
|
||||
foreach ($doc->getTags() as $tag) {
|
||||
if ($tag instanceof Param && !isset($this->params[$tag->getVariableName()])) {
|
||||
$this->params[$tag->getVariableName()] = [
|
||||
$tag->getType(),
|
||||
$tag->getDescription()
|
||||
];
|
||||
} elseif ($tag instanceof Return_ && !isset($this->return)) {
|
||||
$this->return = $tag;
|
||||
} elseif ($tag instanceof Generic && $tag->getName() === 'psalm-return') {
|
||||
$this->psalmReturn = $tag;
|
||||
} elseif ($tag instanceof Generic && $tag->getName() === 'psalm-param') {
|
||||
[$type, $description] = \explode(" $", $tag->getDescription(), 2);
|
||||
$description .= ' ';
|
||||
[$varName, $description] = \explode(" ", $description, 2);
|
||||
if (!$description && isset($this->params[$varName])) {
|
||||
$description = (string) $this->params[$varName][1];
|
||||
} else {
|
||||
$description = new Description($description);
|
||||
}
|
||||
$this->psalmParams[$varName] = [
|
||||
$type,
|
||||
$description
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->params as &$param) {
|
||||
if (isset($param[0])) {
|
||||
$param[0] = $this->resolveTypeAlias($param[0]);
|
||||
}
|
||||
}
|
||||
foreach ($this->psalmParams as &$param) {
|
||||
if (isset($param[0])) {
|
||||
$param[0] = $this->resolveTypeAlias($param[0]);
|
||||
}
|
||||
}
|
||||
if (isset($this->psalmReturn)) {
|
||||
$this->psalmReturn = $this->resolveTypeAlias($this->psalmReturn);
|
||||
}
|
||||
}
|
||||
|
||||
public function getSignature(): string
|
||||
{
|
||||
$sig = $this->name;
|
||||
$sig .= "(";
|
||||
foreach ($this->params as $var => [$type, $description]) {
|
||||
$sig .= $type.' ';
|
||||
$sig .= "$".$var;
|
||||
$sig .= ', ';
|
||||
}
|
||||
$sig = \trim($sig, ', ');
|
||||
$sig .= ')';
|
||||
if (isset($this->return)) {
|
||||
$sig .= ': ';
|
||||
$sig .= $this->resolveTypeAlias($this->return);
|
||||
}
|
||||
return $sig;
|
||||
}
|
||||
public function format(): string
|
||||
{
|
||||
$sig = '### `'.$this->getSignature()."`";
|
||||
$sig .= "\n\n";
|
||||
$sig .= $this->title;
|
||||
$sig .= "\n";
|
||||
$sig .= $this->description;
|
||||
$sig .= "\n";
|
||||
if ($this->psalmParams || $this->params) {
|
||||
$sig .= "\nParameters:\n";
|
||||
foreach ($this->params as $name => [$type, $description]) {
|
||||
$sig .= "* `\$$name`: `$type` $description \n";
|
||||
if (isset($this->psalmParams[$name])) {
|
||||
[$psalmType] = $this->psalmParams[$name];
|
||||
$psalmType = \trim(\str_replace("\n", "\n ", $psalmType));
|
||||
|
||||
$sig .= " Full type:\n";
|
||||
$sig .= " ```\n";
|
||||
$sig .= " $psalmType\n";
|
||||
$sig .= " ```\n";
|
||||
}
|
||||
}
|
||||
$sig .= "\n";
|
||||
}
|
||||
if (isset($this->return) && $this->return->getDescription() && $this->return->getDescription()->render()) {
|
||||
$sig .= "\nReturn value: ".$this->return->getDescription()."\n";
|
||||
}
|
||||
if (isset($this->psalmReturn)) {
|
||||
$sig .= "\nFully typed return value:\n```\n".$this->psalmReturn."\n```";
|
||||
}
|
||||
$sig .= $this->seeAlso();
|
||||
$sig .= "\n";
|
||||
return $sig;
|
||||
}
|
||||
}
|
570
src/PhpDoc/PhpDoc.php
Normal file
570
src/PhpDoc/PhpDoc.php
Normal file
@ -0,0 +1,570 @@
|
||||
<?php
|
||||
/**
|
||||
* PhpDocBuilder module.
|
||||
*
|
||||
* This file is part of PhpDoc.
|
||||
* PhpDoc is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* PhpDoc 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 Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License along with PhpDoc.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||
*
|
||||
* @link https://phpdoc.daniil.it PhpDoc documentation
|
||||
*/
|
||||
|
||||
namespace danog\PhpDoc\PhpDoc;
|
||||
|
||||
use danog\ClassFinder\ClassFinder;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Author;
|
||||
use phpDocumentor\Reflection\DocBlockFactory;
|
||||
use ReflectionClass;
|
||||
use ReflectionFunction;
|
||||
|
||||
class PhpDoc
|
||||
{
|
||||
/**
|
||||
* Namespace.
|
||||
*/
|
||||
private string $namespace;
|
||||
/**
|
||||
* Scan mode.
|
||||
*/
|
||||
private int $mode;
|
||||
/**
|
||||
* Docblock factory.
|
||||
*/
|
||||
private DocBlockFactory $factory;
|
||||
/**
|
||||
* Authors.
|
||||
*/
|
||||
private array $authors = [];
|
||||
/**
|
||||
* Classes/interfaces/traits to ignore.
|
||||
*
|
||||
* @var ?callable
|
||||
* @psalm-var null|callable(class-string)
|
||||
*/
|
||||
private $ignore;
|
||||
/**
|
||||
* Output directory.
|
||||
*/
|
||||
private string $output;
|
||||
/**
|
||||
* Project name.
|
||||
*/
|
||||
private string $name = 'PHPDOC';
|
||||
/**
|
||||
* Project description.
|
||||
*/
|
||||
private string $description = 'PHPDOC documentation';
|
||||
/**
|
||||
* Project image.
|
||||
*/
|
||||
private string $image;
|
||||
/**
|
||||
* Use map.
|
||||
*
|
||||
* @var array<class-string, array<class-string, class-string>>
|
||||
*/
|
||||
private array $useMap = [];
|
||||
/**
|
||||
* Title map.
|
||||
*
|
||||
* @var array<class-string, string>
|
||||
*/
|
||||
private array $titleMap = [];
|
||||
/**
|
||||
* Class map.
|
||||
*
|
||||
* @var array<class-string, bool>
|
||||
*/
|
||||
private array $classMap = [];
|
||||
/**
|
||||
* Create docblock builder.
|
||||
*
|
||||
* @param string $namespace Namespace (defaults to package namespace)
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function fromNamespace(string $namespace = ''): self
|
||||
{
|
||||
return new self($namespace);
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $namespace
|
||||
* @param int $mode
|
||||
*/
|
||||
private function __construct(string $namespace)
|
||||
{
|
||||
$this->factory = DocBlockFactory::createInstance();
|
||||
$this->namespace = $namespace;
|
||||
|
||||
$appRoot = new \danog\ClassFinder\AppConfig;
|
||||
$appRoot = $appRoot->getAppRoot();
|
||||
$appRoot .= "/composer.json";
|
||||
$json = \json_decode(\file_get_contents($appRoot), true);
|
||||
$authors = $json['authors'] ?? [];
|
||||
|
||||
$this->name = $json['name'] ?? '';
|
||||
$this->description = $json['description'] ?? '';
|
||||
foreach ($authors as $author) {
|
||||
$this->authors []= new Author($author['name'], $author['email']);
|
||||
}
|
||||
|
||||
if (!$this->namespace) {
|
||||
$namespaces = \array_keys($json['autoload']['psr-4']);
|
||||
$this->namespace = $namespaces[0];
|
||||
foreach ($namespaces as $namespace) {
|
||||
if (\strlen($namespace) && \strlen($namespace) < \strlen($this->namespace)) {
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set filter to ignore certain classes.
|
||||
*
|
||||
* @param callable $ignore
|
||||
*
|
||||
* @psalm-param callable(class-string) $ignore
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setFilter(callable $ignore): self
|
||||
{
|
||||
$this->ignore = $ignore;
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Set output directory.
|
||||
*
|
||||
* @param string $output Output directory
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setOutput(string $output): self
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Run documentor.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function run(): self
|
||||
{
|
||||
$classList = ClassFinder::getClassesInNamespace($this->namespace, $this->mode | ClassFinder::RECURSIVE_MODE);
|
||||
foreach ($classList as $class) {
|
||||
$this->addTypeAliases($class);
|
||||
}
|
||||
$namespaces = [];
|
||||
foreach ($this->useMap as $orig => $aliases) {
|
||||
$class = \str_replace('\\', '/', $orig);
|
||||
$namespace = \dirname($class);
|
||||
$namespaces[$namespace]['\\'.\basename($class)] = $orig;
|
||||
$namespaces[$namespace][\basename($class)] = $orig;
|
||||
}
|
||||
foreach ($this->useMap as $class => &$aliases) {
|
||||
$class = \str_replace('\\', '/', $class);
|
||||
$namespace = \dirname($class);
|
||||
$aliases = \array_merge($namespaces[$namespace], $aliases);
|
||||
}
|
||||
$final = [];
|
||||
$traits = '';
|
||||
$classes = '';
|
||||
$abstract = '';
|
||||
$interfaces = '';
|
||||
$functions = '';
|
||||
foreach ($classList as $class) {
|
||||
if ($this->ignore && $this->shouldIgnore($class)) {
|
||||
continue;
|
||||
}
|
||||
$reflectionClass = \function_exists($class)
|
||||
? new ReflectionFunction($class)
|
||||
: new ReflectionClass($class);
|
||||
|
||||
$class = $reflectionClass instanceof ReflectionFunction
|
||||
? new FunctionDoc($this, $reflectionClass)
|
||||
: new ClassDoc($this, $reflectionClass);
|
||||
|
||||
if ($class->shouldIgnore()) {
|
||||
continue;
|
||||
}
|
||||
$final[$class->getName()] = $class;
|
||||
$this->titleMap[$class->getResolvedClassName()] = $class->getTitle();
|
||||
$this->classMap[$class->getResolvedClassName()] = true;
|
||||
|
||||
$line = '';
|
||||
$line .= $class->getResolvedClassName();
|
||||
if ($class->getTitle()) {
|
||||
$line .= ": ".$class->getTitle();
|
||||
}
|
||||
$path = $class->getResolvedClassName();
|
||||
$path = \str_replace('\\', '/', \substr($path, 1));
|
||||
$path .= '.md';
|
||||
if ($class instanceof FunctionDoc) {
|
||||
$functions .= "* [$line]($path)\n";
|
||||
} else if ($reflectionClass->isTrait()) {
|
||||
$traits .= "* [$line]($path)\n";
|
||||
} else if ($reflectionClass->isAbstract()) {
|
||||
$abstract .= "* [$line]($path)\n";
|
||||
} else if ($reflectionClass->isInterface()) {
|
||||
$interfaces .= "* [$line]($path)\n";
|
||||
} else {
|
||||
$classes .= "* [$line]($path)\n";
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($final as $class) {
|
||||
$this->generate($class);
|
||||
}
|
||||
|
||||
|
||||
$functions = $functions ? "## Functions\n$functions" : '';
|
||||
$traits = $traits ? "## Traits\n$traits" : '';
|
||||
$abstract = $abstract ? "## Abstract classes\n$abstract" : '';
|
||||
$interfaces = $interfaces ? "## Interfaces\n$interfaces" : '';
|
||||
$functions = $functions ? "## Functions\n$functions" : '';
|
||||
|
||||
$image = $this->getImage();
|
||||
$index = <<<EOF
|
||||
---
|
||||
title: $this->title
|
||||
description: $this->description$image
|
||||
---
|
||||
# `$this->title`
|
||||
|
||||
|
||||
$functions
|
||||
$interfaces
|
||||
$abstract
|
||||
$classes
|
||||
$traits
|
||||
|
||||
EOF;
|
||||
|
||||
$fName = $this->output;
|
||||
$fName .= DIRECTORY_SEPARATOR;
|
||||
$fName .= 'index.md';
|
||||
|
||||
$handle = \fopen(self::createDir($fName), 'w+');
|
||||
\fwrite($handle, $index);
|
||||
\fclose($handle);
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Get title for class.
|
||||
*
|
||||
* @param string $class
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(string $class): string
|
||||
{
|
||||
return $this->titleMap[$class] ?? '';
|
||||
}
|
||||
/**
|
||||
* Check if we are generating docs for this class.
|
||||
*
|
||||
* @param string $class
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasClass(string $class): bool
|
||||
{
|
||||
return isset($this->classMap[$class]);
|
||||
}
|
||||
/**
|
||||
* Resolve type alias.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $fromClass Class from where this function is called
|
||||
* @param string $name Name to resolve
|
||||
* @param string[] $resolved Resolved names
|
||||
*
|
||||
* @psalm-param class-string $fromClass Class from where this function is called
|
||||
* @psalm-param class-string $name Name to resolve
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function resolveTypeAlias(string $fromClass, string $name, array &$resolved): string
|
||||
{
|
||||
if (str_ends_with($name, '[]')) {
|
||||
return $this->resolveTypeAlias($fromClass, \substr($name, 0, -2), $resolved)."[]";
|
||||
}
|
||||
$name = \rtrim(\ltrim($name, '('), ')');
|
||||
if (\count($split = self::splitOnWithoutParenthesis('|', $name)) > 1) {
|
||||
foreach ($split as &$name) {
|
||||
$name = $this->resolveTypeAlias($fromClass, $name, $resolved);
|
||||
}
|
||||
return \implode('|', $split);
|
||||
}
|
||||
if (str_starts_with($name, 'array{')) {
|
||||
$new = '';
|
||||
$split = self::splitOnWithoutParenthesis(',', \substr($name, 6, -1));
|
||||
foreach ($split as $key => $var) {
|
||||
if (\preg_match('/^([^:]+): *(.+)/s', $var, $matches)) {
|
||||
[, $key, $var] = $matches;
|
||||
}
|
||||
$new .= "$key: ".$this->resolveTypeAlias($fromClass, $var, $resolved).", ";
|
||||
}
|
||||
$new = \substr($new, 0, -2);
|
||||
return 'array{'.$new.'}';
|
||||
}
|
||||
if (\preg_match("/([^<]+)[<](.+)[>]$/s", $name, $matches)) {
|
||||
[, $main, $template] = $matches;
|
||||
$newTemplate = '';
|
||||
foreach (self::splitOnWithoutParenthesis(',', $template) as $arg) {
|
||||
$newTemplate .= $this->resolveTypeAlias($fromClass, $arg, $resolved).', ';
|
||||
}
|
||||
$template = \substr($newTemplate, 0, -2);
|
||||
$main = $this->resolveTypeAlias($fromClass, $main, $resolved);
|
||||
return "$main<$template>";
|
||||
}
|
||||
if ($name[0] === '?') {
|
||||
return "?".$this->resolveTypeAlias($fromClass, \substr($name, 1), $resolved);
|
||||
}
|
||||
$res = $this->useMap[$fromClass][$name] ?? $name;
|
||||
if ($res[0] !== '\\' && !self::isScalar($res)) {
|
||||
$res = "\\$res";
|
||||
}
|
||||
$resolved []= $res;
|
||||
return $res;
|
||||
}
|
||||
/**
|
||||
* Split string, without considering separators inside parenthesis.
|
||||
*
|
||||
* @param string $separator
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
private static function splitOnWithoutParenthesis(string $separator, string $type): array
|
||||
{
|
||||
$args = [''];
|
||||
$openCount = 0;
|
||||
for ($x = 0; $x < \strlen($type); $x++) {
|
||||
$char = $type[$x];
|
||||
if ($char === '(' || $char === '<' || $char === '{') {
|
||||
$openCount++;
|
||||
} elseif ($char === ')' || $char === '>' || $char === '}') {
|
||||
$openCount--;
|
||||
} elseif ($char === $separator && !$openCount) {
|
||||
$args []= '';
|
||||
continue;
|
||||
}
|
||||
$args[\count($args)-1] .= $char;
|
||||
}
|
||||
return \array_map('trim', $args);
|
||||
}
|
||||
/**
|
||||
* Check if type is scalar.
|
||||
*
|
||||
* @param string $type
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isScalar(string $type): bool
|
||||
{
|
||||
return \in_array($type, ['string', 'int', 'integer', 'float', 'bool', 'boolean', 'void', 'mixed', 'object', 'callable', 'iterable', 'class-string', 'array', 'array-key', 'static', 'self', 'null', 'true', 'false', 'list']);
|
||||
}
|
||||
/**
|
||||
* Add type alias.
|
||||
*
|
||||
* @param string $class
|
||||
*
|
||||
* @psalm-param class-string $class
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addTypeAliases(string $class)
|
||||
{
|
||||
$reflectionClass = \function_exists($class)
|
||||
? new ReflectionFunction($class)
|
||||
: new ReflectionClass($class);
|
||||
$payload = \file_get_contents($reflectionClass->getFileName());
|
||||
\preg_match_all("/use *(function)? +(.*?)(?: +as +(.+))? *;/", $payload, $matches, PREG_SET_ORDER|PREG_UNMATCHED_AS_NULL);
|
||||
$this->useMap[$class] ??= [];
|
||||
foreach ($matches as [, $function, $import, $alias]) {
|
||||
$import = "\\$import";
|
||||
$alias ??= \basename(\str_replace('\\', '/', $import));
|
||||
$this->useMap[$class][$alias] = $import;
|
||||
$this->useMap[$class]['\\'.$alias] = $import;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create directory recursively.
|
||||
*
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
private static function createDir(string $file): string
|
||||
{
|
||||
$dir = \dirname($file);
|
||||
if (!\file_exists($dir)) {
|
||||
self::createDir($dir);
|
||||
\mkdir($dir);
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate documentation for class.
|
||||
*
|
||||
* @param GenericDoc $class Class
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function generate(GenericDoc $class): void
|
||||
{
|
||||
$name = $class->getName();
|
||||
$fName = $this->output;
|
||||
$fName .= \str_replace('\\', DIRECTORY_SEPARATOR, $name);
|
||||
$fName .= '.md';
|
||||
|
||||
$class = $class->format();
|
||||
|
||||
$handle = \fopen(self::createDir($fName), 'w+');
|
||||
\fwrite($handle, $class);
|
||||
\fclose($handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get docblock factory.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @return DocBlockFactory
|
||||
*/
|
||||
public function getFactory(): DocBlockFactory
|
||||
{
|
||||
return $this->factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether should ignore trait/class/interface.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldIgnore(string $class): bool
|
||||
{
|
||||
return !($this->ignore)($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authors.
|
||||
*
|
||||
* @return Author[]
|
||||
*/
|
||||
public function getAuthors(): array
|
||||
{
|
||||
return $this->authors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set authors.
|
||||
*
|
||||
* @param Author[] $authors Authors
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setAuthors(array $authors): self
|
||||
{
|
||||
$this->authors = $authors;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set scan mode.
|
||||
*
|
||||
* @param int $mode Scan mode.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setMode(int $mode): self
|
||||
{
|
||||
$this->mode = $mode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set project name.
|
||||
*
|
||||
* @param string $name Project name
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setName(string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project description.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set project description.
|
||||
*
|
||||
* @param string $description Project description
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setDescription(string $description): self
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project image (front matter).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getImage(): string
|
||||
{
|
||||
return $this->image ? "image: ".$this->image."\n" : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set project image.
|
||||
*
|
||||
* @param string $image Project image
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setImage(string $image): self
|
||||
{
|
||||
$this->image = $image;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
157
src/PhpDocBuilder.php
Normal file
157
src/PhpDocBuilder.php
Normal file
@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/**
|
||||
* PhpDocBuilder module.
|
||||
*
|
||||
* This file is part of PhpDoc.
|
||||
* PhpDoc is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* PhpDoc 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 Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License along with PhpDoc.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||
*
|
||||
* @link https://phpdoc.daniil.it PhpDoc documentation
|
||||
*/
|
||||
|
||||
namespace danog\PhpDoc;
|
||||
|
||||
use danog\PhpDoc\PhpDoc\PhpDoc;
|
||||
|
||||
final class PhpDocBuilder
|
||||
{
|
||||
/**
|
||||
* PHPDoc instance.
|
||||
*/
|
||||
private PhpDoc $doc;
|
||||
/**
|
||||
* Create docblock builder.
|
||||
*
|
||||
* @param string $namespace Namespace (defaults to package namespace)
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function fromNamespace(string $namespace = ''): self
|
||||
{
|
||||
return new self($namespace);
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $namespace
|
||||
*/
|
||||
private function __construct(string $namespace)
|
||||
{
|
||||
$this->doc = PhpDoc::fromNamespace($namespace);
|
||||
}
|
||||
/**
|
||||
* Set authors.
|
||||
*
|
||||
* @param Author[] $authors Authors
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setAuthors(array $authors): self
|
||||
{
|
||||
$this->doc->setAuthors($authors);
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Set scan mode.
|
||||
*
|
||||
* @param int $mode Scan mode.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setMode(int $mode): self
|
||||
{
|
||||
$this->doc->setMode($mode);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set filter to ignore certain classes.
|
||||
*
|
||||
* @param callable $ignore
|
||||
*
|
||||
* @psalm-param callable(class-string) $ignore
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setFilter(callable $ignore): self
|
||||
{
|
||||
$this->doc->setFilter($ignore);
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Set output directory.
|
||||
*
|
||||
* @param string $output Output directory
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setOutput(string $output): self
|
||||
{
|
||||
$this->doc->setOutput($output);
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Set project name.
|
||||
*
|
||||
* @param string $name Name
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setName(string $name): self
|
||||
{
|
||||
$this->doc->setName($name);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set project description.
|
||||
*
|
||||
* @param string $description Project description
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setDescription(string $description): self
|
||||
{
|
||||
$this->doc->setDescription($description);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set project image.
|
||||
*
|
||||
* @param string $image Project image
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setImage(string $image): self
|
||||
{
|
||||
$this->doc->setImage($image);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run documentation builder.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function run(): self
|
||||
{
|
||||
$this->doc->run();
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user