diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7d3148d..830d229 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,38 +4,55 @@ on: push: paths-ignore: - '**/*.md' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.experimental }} strategy: + fail-fast: false matrix: - emacs_version: - - "26.3" - - "27.1" - - snapshot + os: [ubuntu-latest, macos-latest, windows-latest] + emacs-version: + - 27.2 + - 28.2 + - 29.4 + - 30.1 + experimental: [false] include: - - emacs_version: snapshot - allow_failure: true + - os: ubuntu-latest + emacs-version: snapshot + experimental: true + - os: macos-latest + emacs-version: snapshot + experimental: true + - os: windows-latest + emacs-version: snapshot + experimental: true + exclude: + - os: macos-latest + emacs-version: "27.2" + steps: - uses: actions/setup-python@v2 with: python-version: '3.x' architecture: 'x64' - - uses: purcell/setup-emacs@master + - uses: jcs090218/setup-emacs@master with: - version: ${{ matrix.emacs_version }} + version: ${{ matrix.emacs-version }} - - uses: conao3/setup-cask@master + - uses: emacs-eask/setup-eask@master with: version: 'snapshot' - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Run make - uses: nick-invision/retry@v2 - with: - timeout_seconds: 90 - max_attempts: 3 - command: 'cask && make' + run: 'make all' diff --git a/.gitignore b/.gitignore index e9d3537..ec6fd1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ *.elc /*-autoloads.el /.cask +/.eask +/dist /composer.lock /vendor diff --git a/CHANGELOG.md b/CHANGELOG.md index d6ec178..e78734a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,41 @@ # Changelog -All notable changes of the phpactor.el are documented in this file using the [Keep a Changelog](https://keepachangelog.com/) principles. +All notable changes of the `phpstan.el` are documented in this file using the [Keep a Changelog](https://keepachangelog.com/) principles. -## Unreleased + + +## [0.8.1] + +### Added + +* Add `phpstan-enable-remote-experimental` custom variable for activate PHPStan on TRAMP. +* Add support for `php-ts-mode`. +* Add `phpstan-insert-dumptype` command +* Add `phpstan-insert-ignore` command + +### Changed + +* Refactored `phpstan-check-buffer` command for improved performance. +* Improved logic for detecting phpstan executable. + +### Removed + +* Drop support for Emacs 24.3. + +## [0.7.0] ### Added * Add `phpstan-analyze-this-file` command * Add `phpstan.dist.neon` to `phpstan-get-config-file` as PHPStan config files. * Add `phpstan-pro` command to launch [PHPStan Pro]. +* Add `phpstan-find-baseline-file` command. +* Add `phpstan-generate-baseline-file` command. [PHPStan Pro]: https://phpstan.org/blog/introducing-phpstan-pro ### Changed * Make flycheck analyze the original file directly instead of temporary files when there are no changes to the file. +* [Internal] Use JSON format for flycheck-phpstan. + * Support **💡 tips** diff --git a/Cask b/Cask deleted file mode 100644 index 3768fee..0000000 --- a/Cask +++ /dev/null @@ -1,9 +0,0 @@ -(package "phpstan" "0.7.2" "Interface to PHPStan (PHP static analyzer)") -(source melpa) -(source gnu) - -(package-file "phpstan.el") -(package-file "flycheck-phpstan.el") -(package-file "flymake-phpstan.el") -(development - (depends-on "php-mode")) diff --git a/Eask b/Eask new file mode 100644 index 0000000..e9f7321 --- /dev/null +++ b/Eask @@ -0,0 +1,22 @@ +(package "phpstan" + "0.7.2" + "Interface to PHPStan (PHP static analyzer)") + +(website-url "https://github.com/emacs-php/phpstan.el") +(keywords "tools" "php") + +(package-file "phpstan.el") +(files "*.el") + +(script "test" "echo \"Error: no test specified\" && exit 1") + +(source 'gnu) +(source 'melpa) + +(depends-on "emacs" "24.3") +(depends-on "compat") +(depends-on "php-mode") +(depends-on "php-runtime") +(depends-on "flycheck") + +(setq network-security-level 'low) ; see https://github.com/jcs090218/setup-emacs-windows/issues/156#issuecomment-932956432 diff --git a/Makefile b/Makefile index 40be38e..a5e34cc 100644 --- a/Makefile +++ b/Makefile @@ -1,34 +1,21 @@ EMACS ?= emacs CASK ?= cask -ELS = phpstan.el flycheck-phpstan.el flymake-phpstan.el -AUTOLOADS = phpstan-autoloads.el -ELCS = $(ELS:.el=.elc) +EASK ?= eask -.el.elc: .cask - $(EMACS) -Q -batch -L . --eval \ - "(let ((default-directory (expand-file-name \".cask\" default-directory))) \ - (require 'package) \ - (normal-top-level-add-subdirs-to-load-path))" \ - -f package-initialize -f batch-byte-compile $< +install: + $(EASK) package + $(EASK) install + $(EASK) install-deps -.cask: Cask - $(CASK) +compile: + $(EASK) compile -all: clean autoloads $(ELCS) +all: clean autoloads install compile -autoloads: $(AUTOLOADS) - -$(AUTOLOADS): $(ELCS) - $(EMACS) -Q -batch -L . --eval \ - "(progn \ - (require 'package) \ - (normal-top-level-add-subdirs-to-load-path) \ - (package-generate-autoloads \"phpstan\" default-directory))" +autoloads: + $(EASK) generate autoloads clean: - -rm -f $(ELCS) $(AUTOLOADS) - -clobber: clean - -rm -f .cask + $(EASK) clean all -.PHONY: all autoloads clean clobber +.PHONY: all autoloads clean diff --git a/README.org b/README.org index 818f4a9..9a6efb1 100644 --- a/README.org +++ b/README.org @@ -5,7 +5,7 @@ #+END_HTML Emacs interface to [[https://github.com/phpstan/phpstan][PHPStan]], includes checker for [[http://www.flycheck.org/en/latest/][Flycheck]]. ** Support version -- Emacs 24+ +- Emacs 25+ - PHPStan latest/dev-master (NOT support 0.9 seriese) - PHP 7.1+ or Docker runtime ** How to install @@ -88,7 +88,23 @@ Typically, you would set the following ~.dir-locals.el~. #+END_SRC If there is a ~phpstan.neon~ file in the root directory of the project, you do not need to set both ~phpstan-working-dir~ and ~phpstan-config-file~. +** Commands +This package provides convenient commands for using PHPStan from Emacs. +*** Command ~phpstan-insert-dumptype~ +Add ~\PHPStan\dumpType(...);~ to your PHP code and analyze it to make PHPStan display the type of the expression. +#+BEGIN_SRC +(define-key php-mode-map (kbd "C-c ^") #'phpstan-insert-dumptype) +#+END_SRC + +By default, if you press ~C-u~ before invoking the command, ~\PHPStan\dumpPhpDocType()~ will be inserted. + +This feature was added in *PHPStan 1.12.7* and will dump types compatible with the ~@param~ and ~@return~ PHPDoc tags. +*** Command ~phpstan-insert-ignore~ +Insert a ~@phpstan-ignore~ tag to suppress any PHPStan errors on the current line. + +By default it inserts the tag on the previous line, but if there is already a tag at the end of the current line or on the previous line, the identifiers will be appended there. +If there is no existing tag and ~C-u~ is pressed before the command, it will be inserted at the end of the line. ** API Most variables defined in this package are buffer local. If you want to set it for multiple projects, use [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Default-Value.html][setq-default]]. diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index 9014baf..49431b8 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -45,6 +45,18 @@ (defvar flycheck-phpstan-executable) (defvar flycheck-phpstan--temp-buffer-name "*Flycheck PHPStan*") +(defcustom flycheck-phpstan-ignore-metadata-list nil + "Set of metadata items to ignore in PHPStan messages for Flycheck." + :type '(set (const identifier) + (const tip)) + :group 'phpstan) + +(defcustom flycheck-phpstan-metadata-separator "\n" + "Separator of PHPStan message and metadata." + :type 'string + :safe #'stringp + :group 'phpstan) + (defun flycheck-phpstan--enabled-and-set-variable () "Return path to phpstan configure file, and set buffer execute in side effect." (let ((enabled (phpstan-enabled))) @@ -63,35 +75,42 @@ (defun flycheck-phpstan-parse-output (output &optional _checker _buffer) "Parse PHPStan errors from OUTPUT." - (with-current-buffer (flycheck-phpstan--temp-buffer) - (erase-buffer) - (insert output)) - (flycheck-phpstan-parse-json (flycheck-phpstan--temp-buffer))) + (let* ((json-buffer (with-current-buffer (flycheck-phpstan--temp-buffer) + (erase-buffer) + (insert output) + (current-buffer))) + (data (phpstan--parse-json json-buffer)) + (errors (phpstan--plist-to-alist (plist-get data :files)))) + (unless phpstan-disable-buffer-errors + (phpstan-update-ignorebale-errors-from-json-buffer errors)) + (flycheck-phpstan--build-errors errors))) (defun flycheck-phpstan--temp-buffer () "Return a temporary buffer for decode JSON." (get-buffer-create flycheck-phpstan--temp-buffer-name)) -(defun flycheck-phpstan-parse-json (json-buffer) - "Parse PHPStan errors from JSON-BUFFER." - (let ((data (phpstan--parse-json json-buffer))) - (cl-loop for (file . entry) in (flycheck-phpstan--plist-to-alist (plist-get data :files)) - append (cl-loop for messages in (plist-get entry :messages) - for text = (let ((msg (plist-get messages :message)) - (tip (plist-get messages :tip))) - (if tip - (concat msg "\n" phpstan-tip-message-prefix tip) - msg)) - collect (flycheck-error-new-at (plist-get messages :line) - nil 'error text - :filename file))))) - -(defun flycheck-phpstan--plist-to-alist (plist) - "Convert PLIST to association list." - (let (alist) - (while plist - (push (cons (substring-no-properties (symbol-name (pop plist)) 1) (pop plist)) alist)) - (nreverse alist))) +(defun flycheck-phpstan--build-errors (errors) + "Build Flycheck errors from PHPStan ERRORS." + (cl-loop for (file . entry) in errors + append (cl-loop for messages in (plist-get entry :messages) + for text = (let* ((msg (plist-get messages :message)) + (ignorable (plist-get messages :ignorable)) + (identifier (unless (memq 'identifier flycheck-phpstan-ignore-metadata-list) + (plist-get messages :identifier))) + (tip (unless (memq 'tip flycheck-phpstan-ignore-metadata-list) + (plist-get messages :tip))) + (lines (list (when (and identifier ignorable) + (concat phpstan-identifier-prefix identifier)) + (when tip + (concat phpstan-tip-message-prefix tip)))) + (lines (cl-remove-if #'null lines))) + (if (null lines) + msg + (concat msg flycheck-phpstan-metadata-separator + (mapconcat #'identity lines "\n")))) + collect (flycheck-error-new-at (plist-get messages :line) + nil 'error text + :filename file)))) (flycheck-define-checker phpstan "PHP static analyzer based on PHPStan." @@ -103,7 +122,7 @@ :working-directory (lambda (_) (phpstan-get-working-dir)) :enabled (lambda () (flycheck-phpstan--enabled-and-set-variable)) :error-parser flycheck-phpstan-parse-output - :modes (php-mode phps-mode)) + :modes (php-mode php-ts-mode phps-mode)) (add-to-list 'flycheck-checkers 'phpstan t) (flycheck-add-next-checker 'php 'phpstan) diff --git a/flymake-phpstan.el b/flymake-phpstan.el index f3f6a15..d1dc8ee 100644 --- a/flymake-phpstan.el +++ b/flymake-phpstan.el @@ -90,15 +90,19 @@ (defun flymake-phpstan (report-fn &rest _ignored-args) "Flymake backend for PHPStan report using REPORT-FN." - (let ((command-args (phpstan-get-command-args t))) + (let ((command-args (phpstan-get-command-args :include-executable t))) (unless (car command-args) (user-error "Cannot find a phpstan executable command")) (when (process-live-p flymake-phpstan--proc) (kill-process flymake-phpstan--proc)) - (let ((source (current-buffer))) + (let ((source (current-buffer)) + (target-path (if (or (buffer-modified-p) (not buffer-file-name)) + (phpstan-normalize-path + (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)) + buffer-file-name))) (save-restriction (widen) - (setq flymake-phpstan--proc (flymake-phpstan-make-process (php-project-get-root-dir) command-args report-fn source)) + (setq flymake-phpstan--proc (flymake-phpstan-make-process (php-project-get-root-dir) (append command-args (list "--" target-path)) report-fn source)) (process-send-region flymake-phpstan--proc (point-min) (point-max)) (process-send-eof flymake-phpstan--proc))))) diff --git a/phpstan.el b/phpstan.el index bea7c27..c7d6f8f 100644 --- a/phpstan.el +++ b/phpstan.el @@ -7,7 +7,7 @@ ;; Version: 0.7.2 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el -;; Package-Requires: ((emacs "24.3") (compat "29") (php-mode "1.22.3") (php-runtime "0.2")) +;; Package-Requires: ((emacs "25.1") (compat "29") (php-mode "1.22.3") (php-runtime "0.2")) ;; License: GPL-3.0-or-later ;; This program is free software; you can redistribute it and/or modify @@ -56,6 +56,7 @@ (require 'cl-lib) (require 'php-project) (require 'php-runtime) +(require 'seq) (eval-when-compile (require 'compat nil t) @@ -129,8 +130,44 @@ :safe #'stringp :group 'phpstan) +(defcustom phpstan-identifier-prefix "🪪 " + "Prefix of PHPStan error identifier." + :type 'string + :safe #'stringp + :group 'phpstan) + +(defcustom phpstan-enable-remote-experimental nil + "Enable PHPStan analysis remotely by TRAMP. + +When non-nil, PHPStan will be executed on a remote server for code analysis. +This feature is experimental and should be used with caution as it may +have unexpected behaviors or performance implications." + :type 'boolean + :safe #'booleanp + :group 'phpstan) + +(defconst phpstan-template-dump-type "\\PHPStan\\dumpType();") +(defconst phpstan-template-dump-phpdoc-type "\\PHPStan\\dumpPhpDocType();") + +(defcustom phpstan-intert-dump-type-templates (cons phpstan-template-dump-type + phpstan-template-dump-phpdoc-type) + "Default template of PHPStan dumpType insertion." + :type '(cons string string) + :group 'phpstan) + +(defcustom phpstan-disable-buffer-errors nil + "If T, don't keep errors per buffer to save memory." + :type 'boolean + :group 'phpstan) + +(defcustom phpstan-not-ignorable-identifiers '("ignore.parseError") + "A list of identifiers that are prohibited from being added to the @phpstan-ignore tag." + :type '(repeat string)) + (defvar-local phpstan--use-xdebug-option nil) +(defvar-local phpstan--ignorable-errors '()) + ;;;###autoload (progn (defvar phpstan-working-dir nil @@ -246,6 +283,18 @@ NIL (and (stringp (car v)) (listp (cdr v)))) (or (eq 'docker v) (null v) (stringp v)))))) +;; Utilities: +(defun phpstan--plist-to-alist (plist) + "Convert PLIST to association list." + (let (alist) + (while plist + (push (cons (substring-no-properties (symbol-name (pop plist)) 1) (pop plist)) alist)) + (nreverse alist))) + +(defsubst phpstan--current-line () + "Return the current buffer line at point. The first line is 1." + (line-number-at-pos nil t)) + ;; Functions: (defun phpstan-get-working-dir () "Return path to working directory of PHPStan." @@ -257,11 +306,12 @@ NIL (defun phpstan-enabled () "Return non-NIL if PHPStan configured or Composer detected." - (and (not (file-remote-p default-directory)) ;; Not support remote filesystem - (or (phpstan-get-config-file) - (phpstan-get-autoload-file) - (and phpstan-enable-on-no-config-file - (php-project-get-root-dir))))) + (unless (and (not phpstan-enable-remote-experimental) + (file-remote-p default-directory)) ;; Not support remote filesystem by default + (or (phpstan-get-config-file) + (phpstan-get-autoload-file) + (and phpstan-enable-on-no-config-file + (php-project-get-root-dir))))) (defun phpstan-get-config-file () "Return path to phpstan configure file or NIL." @@ -334,21 +384,28 @@ it returns the value of `SOURCE' as it is." (let ((json-object-type 'plist) (json-array-type 'list)) (json-read-object))))) +(defun phpstan--expand-file-name (name) + "Expand file name by NAME." + (let ((file (expand-file-name name))) + (if (file-remote-p name) + (tramp-file-name-localname (tramp-dissect-file-name name)) + (expand-file-name file)))) + ;;;###autoload (defun phpstan-analyze-this-file () "Analyze current buffer-file using PHPStan." (interactive) - (let ((file (expand-file-name (or buffer-file-name - (read-file-name "Choose a PHP script: "))))) + (let ((file (phpstan--expand-file-name (or buffer-file-name + (read-file-name "Choose a PHP script: "))))) (compile (mapconcat #'shell-quote-argument - (phpstan-get-command-args :include-executable t :args (list file)) " ")))) + (phpstan-get-command-args :include-executable t :args (list file) :verbose 1) " ")))) ;;;###autoload (defun phpstan-analyze-file (file) "Analyze a PHP script FILE using PHPStan." - (interactive (list (expand-file-name (read-file-name "Choose a PHP script: ")))) + (interactive (list (phpstan--expand-file-name (read-file-name "Choose a PHP script: ")))) (compile (mapconcat #'shell-quote-argument - (phpstan-get-command-args :include-executable t :args (list file)) " "))) + (phpstan-get-command-args :include-executable t :args (list file) :verbose 1) " "))) ;;;###autoload (defun phpstan-analyze-project () @@ -411,17 +468,18 @@ it returns the value of `SOURCE' as it is." (listp (cdr phpstan-executable))) (cdr phpstan-executable)) ((null phpstan-executable) - (let ((vendor-phpstan (expand-file-name "vendor/bin/phpstan" - (php-project-get-root-dir)))) + (let* ((vendor-phpstan (expand-file-name "vendor/bin/phpstan" + (php-project-get-root-dir))) + (expanded-vendor-phpstan (phpstan--expand-file-name vendor-phpstan))) (cond ((file-exists-p vendor-phpstan) (if (file-executable-p vendor-phpstan) - (list vendor-phpstan) - (list php-executable vendor-phpstan))) + (list expanded-vendor-phpstan) + (list php-executable expanded-vendor-phpstan))) ((executable-find "phpstan") (list (executable-find "phpstan"))) (t (error "PHPStan executable not found"))))))) -(cl-defun phpstan-get-command-args (&key include-executable use-pro args format options config) +(cl-defun phpstan-get-command-args (&key include-executable use-pro args format options config verbose) "Return command line argument for PHPStan." (let ((executable-and-args (phpstan-get-executable-and-args)) (config (or config (phpstan-normalize-path (phpstan-get-config-file)))) @@ -434,10 +492,16 @@ it returns the value of `SOURCE' as it is." (format "--error-format=%s" (or format "raw")) "--no-progress" "--no-interaction") (and use-pro (list "--pro" "--no-ansi")) - (and config (list "-c" config)) + (and config (list "-c" (phpstan--expand-file-name config))) (and autoload (list "-a" autoload)) (and memory-limit (list "--memory-limit" memory-limit)) (and level (list "-l" level)) + (cond + ((null verbose) nil) + ((memq verbose '(1 t)) (list "-v")) + ((eq verbose 2) (list "-vv")) + ((eq verbose 3) (list "-vvv")) + ((error ":verbose option should be 1, 2, 3 or `t'"))) (cond (phpstan--use-xdebug-option (list phpstan--use-xdebug-option)) ((eq phpstan-use-xdebug-option 'auto) @@ -449,5 +513,103 @@ it returns the value of `SOURCE' as it is." options (and args (cons "--" args))))) +(defun phpstan-update-ignorebale-errors-from-json-buffer (errors) + "Update `phpstan--ignorable-errors' variable by ERRORS." + (let ((identifiers + (cl-loop for (_ . entry) in errors + append (cl-loop for message in (plist-get entry :messages) + if (plist-get message :ignorable) + collect (cons (plist-get message :line) + (plist-get message :identifier)))))) + (setq phpstan--ignorable-errors + (mapcar (lambda (v) (cons (car v) (mapcar #'cdr (cdr v)))) (seq-group-by #'car identifiers))))) + +(defconst phpstan--re-ignore-tag + (eval-when-compile + (rx (* (syntax whitespace)) "//" (* (syntax whitespace)) + (group "@phpstan-ignore") + (* (syntax whitespace)) + (* (not "(")) + (group (? (+ (syntax whitespace) "(")))))) + +(cl-defun phpstan--check-existing-ignore-tag (&key in-previous) + "Check existing @phpstan-ignore PHPDoc tag. +If IN-PREVIOUS is NIL, check the previous line for the tag." + (let ((new-position (if in-previous 'previous-line 'this-line)) + (line-end (line-end-position)) + new-point append) + (save-excursion + (save-match-data + (if (re-search-forward phpstan--re-ignore-tag line-end t) + (progn + (setq new-point (match-beginning 2)) + (goto-char new-point) + (when (eq (char-syntax (char-before)) ?\ ) + (left-char) + (setq new-point (point))) + (setq append (not (eq (match-end 1) (match-beginning 2)))) + (cl-values new-position new-point append)) + (if in-previous + (cl-values nil nil nil) + (previous-logical-line) + (beginning-of-line) + (phpstan--check-existing-ignore-tag :in-previous t))))))) + +;;;###autoload +(defun phpstan-insert-ignore (position) + "Insert an @phpstan-ignore comment at the specified POSITION. + +POSITION determines where to insert the comment and can be either `this-line' or +`previous-line'. + +- If POSITION is `this-line', the comment is inserted at the end of + the current line. +- If POSITION is `previous-line', the comment is inserted on a new line above + the current line." + (interactive + (list (if current-prefix-arg 'this-line 'previous-line))) + (save-restriction + (widen) + (let ((pos (point)) + (identifiers (cl-set-difference (alist-get (phpstan--current-line) phpstan--ignorable-errors) phpstan-not-ignorable-identifiers :test #'equal)) + (padding (if (eq position 'this-line) " " "")) + new-position new-point delete-region) + (cl-multiple-value-setq (new-position new-point append) (phpstan--check-existing-ignore-tag :in-previous nil)) + (when new-position + (setq position new-position)) + (unless (and append (null identifiers)) + (if (not new-point) + (cond + ((eq position 'this-line) (end-of-line)) + ((eq position 'previous-line) (progn + (previous-logical-line) + (end-of-line) + (newline-and-indent))) + ((error "Unexpected position: %s" position))) + (setq padding "") + (goto-char new-point)) + (insert (concat padding + (if new-position (if append ", " " ") "// @phpstan-ignore ") + (mapconcat #'identity identifiers ", "))))))) + +;;;###autoload +(defun phpstan-insert-dumptype (&optional expression prefix-num) + "Insert PHPStan\\dumpType() expression-statement by EXPRESSION and PREFIX-NUM." + (interactive + (list + (if (region-active-p) + (buffer-substring-no-properties (region-beginning) (region-end)) + (or (thing-at-point 'symbol t) "")) + current-prefix-arg)) + (let ((template (if prefix-num + (cdr phpstan-intert-dump-type-templates) + (car phpstan-intert-dump-type-templates)))) + (end-of-line) + (newline-and-indent) + (insert template) + (search-backward "(" (line-beginning-position) t) + (forward-char) + (insert expression))) + (provide 'phpstan) ;;; phpstan.el ends here diff --git a/tests/phpstan-docker.neon b/tests/phpstan-docker.neon index 356d55c..ff593e8 100644 --- a/tests/phpstan-docker.neon +++ b/tests/phpstan-docker.neon @@ -1,2 +1,3 @@ parameters: - bootstrap: %currentWorkingDirectory%/../app/tests/bootstrap.php + bootstrapFiles: + - %currentWorkingDirectory%/../app/tests/bootstrap.php diff --git a/tests/phpstan.neon b/tests/phpstan.neon index 2b4b28c..53c205f 100644 --- a/tests/phpstan.neon +++ b/tests/phpstan.neon @@ -1,2 +1,3 @@ parameters: - bootstrap: %rootDir%/../../../tests/bootstrap.php + bootstrapFiles: + - %rootDir%/../../../tests/bootstrap.php