├── Api └── Data │ └── LogInterface.php ├── Console └── Command │ └── CleanCommand.php ├── Controller └── Adminhtml │ └── Reports │ ├── Delete.php │ ├── Detail.php │ └── Index.php ├── Cron └── CleanCron.php ├── LICENSE ├── Model ├── Clean.php ├── Config.php ├── Config │ └── Source │ │ ├── Code.php │ │ ├── Methods.php │ │ └── RequestorIp.php ├── Log.php ├── Log │ └── Logger.php ├── LogHandle.php ├── ResourceModel │ ├── Entity │ │ └── LogCollection.php │ └── LogResourceModel.php └── SecretParser.php ├── Plugin ├── FrontControllerDispatchAfter.php └── FrontControllerDispatchBefore.php ├── README.md ├── Ui ├── Component │ └── Listing │ │ └── Column │ │ ├── Datetime.php │ │ └── RowAction.php └── DataProvider │ └── LogListingDataProvider.php ├── ViewModel └── Detail.php ├── composer.json ├── etc ├── acl.xml ├── adminhtml │ ├── menu.xml │ ├── routes.xml │ └── system.xml ├── config.xml ├── crontab.xml ├── db_schema.xml ├── di.xml └── module.xml ├── registration.php ├── screenshots ├── screen1.png ├── screen2.png ├── screen3.png └── screen4.png └── view └── adminhtml ├── layout ├── webapi_logs_reports_detail.xml └── webapi_logs_reports_index.xml ├── templates └── detail.phtml ├── ui_component └── webapi_logs_reports_index_listing.xml └── web ├── js ├── grid │ └── columns │ │ └── select.js └── js-beautify │ └── beautify.min.js └── template └── ui └── grid └── cells └── text.html /Api/Data/LogInterface.php: -------------------------------------------------------------------------------- 1 | clean = $clean; 32 | parent::__construct($name); 33 | } 34 | 35 | /** 36 | * @inheritDoc 37 | */ 38 | protected function configure() 39 | { 40 | $this->setDescription('WebapiLogs Cleaner'); 41 | parent::configure(); 42 | } 43 | 44 | /** 45 | * @param InputInterface $input 46 | * @param OutputInterface $output 47 | * @throws \Exception 48 | */ 49 | protected function execute(InputInterface $input, OutputInterface $output) 50 | { 51 | $this->clean->execute(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Reports/Delete.php: -------------------------------------------------------------------------------- 1 | resultPageFactory = $resultPageFactory; 55 | $this->logCollectionFactory = $logCollectionFactory; 56 | $this->logger = $logger; 57 | } 58 | 59 | /** 60 | * @inheritDoc 61 | */ 62 | public function execute() 63 | { 64 | try { 65 | $logs = $this->logCollectionFactory->create(); 66 | foreach ($logs as $log) { 67 | $log->delete(); 68 | } 69 | } catch (Exception $exception) { 70 | $this->logger->error(__('Cant delete webapi log because of error: %1', $exception->getMessage())); 71 | } 72 | 73 | $resultRedirect = $this->resultRedirectFactory->create(); 74 | return $resultRedirect->setPath('*/*/index', ['_current' => true]); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Reports/Detail.php: -------------------------------------------------------------------------------- 1 | resultPageFactory = $resultPageFactory; 40 | } 41 | 42 | /** 43 | * @return Page|ResultInterface 44 | */ 45 | public function execute() 46 | { 47 | $resultPage = $this->resultPageFactory->create(); 48 | $resultPage->setActiveMenu('GhostUnicorns_WebapiLogs::reports'); 49 | $resultPage->getConfig()->getTitle()->prepend(__('Webapi REST api logs')); 50 | return $resultPage; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Reports/Index.php: -------------------------------------------------------------------------------- 1 | resultPageFactory = $resultPageFactory; 40 | } 41 | 42 | /** 43 | * @return Page|ResultInterface 44 | */ 45 | public function execute() 46 | { 47 | $resultPage = $this->resultPageFactory->create(); 48 | $resultPage->setActiveMenu('GhostUnicorns_WebapiLogs::reports'); 49 | $resultPage->getConfig()->getTitle()->prepend(__('Webapi REST api logs')); 50 | return $resultPage; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Cron/CleanCron.php: -------------------------------------------------------------------------------- 1 | clean = $clean; 28 | } 29 | 30 | /** 31 | * @throws Exception 32 | */ 33 | public function execute() 34 | { 35 | $this->clean->execute(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ghost Unicorns snc di Ugolini Riccardo e Argentiero Danilo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Model/Clean.php: -------------------------------------------------------------------------------- 1 | config = $config; 52 | $this->logger = $logger; 53 | $this->logCollectionFactory = $logCollectionFactory; 54 | $this->logResourceModel = $logResourceModel; 55 | } 56 | 57 | /** 58 | * @throws Exception 59 | */ 60 | public function execute() 61 | { 62 | if (!$this->config->isEnabled()) { 63 | return; 64 | } 65 | 66 | $this->logger->info(__('Start webapi logs clean')); 67 | $hours = $this->config->getCleanOlderThanHours(); 68 | $datetime = new DateTime('-' . $hours . ' hour'); 69 | $page = 1; 70 | 71 | $collection = $this->logCollectionFactory->create(); 72 | $collection = $collection->addFieldToSelect(LogResourceModel::LOG_ID) 73 | ->addFieldToFilter(LogResourceModel::CREATED_AT, ['lt' => $datetime]) 74 | ->setPageSize(1000); 75 | 76 | $pageCount = $collection->getLastPageNumber(); 77 | $currentPage = 1; 78 | $tot = 0; 79 | while ($currentPage <= $pageCount) { 80 | $collection->setCurPage($currentPage); 81 | foreach ($collection as $row) { 82 | $this->logResourceModel->delete($row); 83 | $tot++; 84 | } 85 | $collection->clear(); 86 | $currentPage++; 87 | } 88 | 89 | $this->logger->info(__('End webapi logs clean. Deleted %1 elements.', $tot)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Model/Config.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 55 | } 56 | 57 | /** 58 | * @return bool 59 | */ 60 | public function isEnabled(): bool 61 | { 62 | return $this->scopeConfig->isSetFlag( 63 | self::WEBAPI_LOGS_IS_ENABLED_CONFIG_PATH, 64 | ScopeInterface::SCOPE_WEBSITE 65 | ); 66 | } 67 | 68 | public function isAjaxCallsDisabled(): bool 69 | { 70 | return $this->scopeConfig->isSetFlag( 71 | self::WEBAPI_LOGS_DISABLED_AJAX_CALLS, 72 | ScopeInterface::SCOPE_WEBSITE 73 | ); 74 | } 75 | 76 | 77 | /** 78 | * @return bool 79 | */ 80 | public function isSecretMode(): bool 81 | { 82 | return $this->scopeConfig->isSetFlag( 83 | self::WEBAPI_LOGS_LOG_SECRET_MODE, 84 | ScopeInterface::SCOPE_WEBSITE 85 | ); 86 | } 87 | 88 | /** 89 | * @return array 90 | */ 91 | public function getSecrets(): array 92 | { 93 | $secrets = $this->scopeConfig->getValue( 94 | self::WEBAPI_LOGS_LOG_SECRET_WORDS, 95 | ScopeInterface::SCOPE_WEBSITE 96 | ); 97 | return preg_split('/\n|\r\n?/', $secrets); 98 | } 99 | 100 | /** 101 | * @return int 102 | */ 103 | public function getCleanOlderThanHours(): int 104 | { 105 | return (int)$this->scopeConfig->getValue( 106 | self::WEBAPI_LOGS_LOG_CLEAN_OLDER_THAN_HOURS, 107 | ScopeInterface::SCOPE_WEBSITE 108 | ); 109 | } 110 | 111 | /** 112 | * @return array 113 | */ 114 | public function getFilterRequestPaths(): array 115 | { 116 | $value = $this->scopeConfig->getValue( 117 | self::WEBAPI_LOGS_LOG_FILTER_REQUEST_PATHS, 118 | ScopeInterface::SCOPE_WEBSITE 119 | ); 120 | if ($value == null) { 121 | return []; 122 | } 123 | return preg_split('/\n|\r\n?/', $value); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /Model/Config/Source/Code.php: -------------------------------------------------------------------------------- 1 | logCollectionFactory = $logCollectionFactory; 29 | } 30 | 31 | /** 32 | * @return array 33 | */ 34 | public function toOptionArray(): array 35 | { 36 | $result = []; 37 | /** @var LogCollection $logsCollection */ 38 | $logsCollection = $this->logCollectionFactory->create(); 39 | $logsCollection->addFieldToSelect('response_code'); 40 | $logsCollection->distinct(true); 41 | foreach ($logsCollection as $logs) { 42 | $result[] = [ 43 | 'value' => $logs->getResponseCode(), 44 | 'label' => $logs->getResponseCode() 45 | ]; 46 | } 47 | return $result; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Model/Config/Source/Methods.php: -------------------------------------------------------------------------------- 1 | logCollectionFactory = $logCollectionFactory; 29 | } 30 | 31 | /** 32 | * @return array 33 | */ 34 | public function toOptionArray(): array 35 | { 36 | $result = []; 37 | /** @var LogCollection $logsCollection */ 38 | $logsCollection = $this->logCollectionFactory->create(); 39 | $logsCollection->addFieldToSelect('request_method'); 40 | $logsCollection->distinct(true); 41 | foreach ($logsCollection as $logs) { 42 | $result[] = [ 43 | 'value' => $logs->getRequestMethod(), 44 | 'label' => $logs->getRequestMethod() 45 | ]; 46 | } 47 | return $result; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Model/Config/Source/RequestorIp.php: -------------------------------------------------------------------------------- 1 | logCollectionFactory = $logCollectionFactory; 29 | } 30 | 31 | /** 32 | * @return array 33 | */ 34 | public function toOptionArray(): array 35 | { 36 | $result = []; 37 | /** @var LogCollection $logsCollection */ 38 | $logsCollection = $this->logCollectionFactory->create(); 39 | $logsCollection->addFieldToSelect('requestor_ip'); 40 | $logsCollection->distinct(true); 41 | foreach ($logsCollection as $logs) { 42 | $result[] = [ 43 | 'value' => $logs->getRequestorIp(), 44 | 'label' => $logs->getRequestorIp() 45 | ]; 46 | } 47 | return $result; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Model/Log.php: -------------------------------------------------------------------------------- 1 | _init(LogResourceModel::class); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Model/Log/Logger.php: -------------------------------------------------------------------------------- 1 | logFactory = $logFactory; 59 | $this->logResourceModel = $logResourceModel; 60 | $this->config = $config; 61 | $this->logger = $logger; 62 | $this->secretParser = $secretParser; 63 | } 64 | 65 | /** 66 | * @param string $requestMethod 67 | * @param string $requestorIp 68 | * @param string $requestPath 69 | * @param string $requestHeaders 70 | * @param string $requestBody 71 | * @param string $requestDateTime 72 | */ 73 | public function before( 74 | string $requestMethod, 75 | string $requestorIp, 76 | string $requestPath, 77 | string $requestHeaders, 78 | string $requestBody, 79 | string $requestDateTime 80 | ) { 81 | $filter = $this->config->getFilterRequestPaths(); 82 | 83 | // Only log this request if the path is not filtered. 84 | if (!$this->filterRequestPath($requestPath, $filter)) { 85 | if ($this->config->isSecretMode()) { 86 | $requestorIp = $this->secretParser->parseIp(); 87 | $requestHeaders = $this->secretParser->parseHeades($requestHeaders); 88 | $requestBody = $this->secretParser->parseBody($requestBody); 89 | } 90 | 91 | $log = $this->logFactory->create(); 92 | $log->setData([ 93 | 'request_method' => $requestMethod, 94 | 'requestor_ip' => $requestorIp, 95 | 'request_url' => $requestPath, 96 | 'request_headers' => $requestHeaders, 97 | 'request_body' => $requestBody, 98 | 'request_datetime' => $requestDateTime 99 | ]); 100 | $this->lastLog = $log; 101 | } 102 | } 103 | 104 | /** 105 | * @param string $responseCode 106 | * @param string $resposeBody 107 | * @param string $responseDateTime 108 | */ 109 | public function after( 110 | string $responseCode, 111 | string $resposeBody, 112 | string $responseDateTime 113 | ) { 114 | if (!$this->lastLog) { 115 | return; 116 | } 117 | 118 | try { 119 | if ($this->config->isSecretMode()) { 120 | $resposeBody = $this->secretParser->parseBody($resposeBody); 121 | } 122 | 123 | $this->lastLog->setResponseBody($resposeBody); 124 | $this->lastLog->setResponseCode($responseCode); 125 | $this->lastLog->setResponseDatetime($responseDateTime); 126 | $this->logResourceModel->save($this->lastLog); 127 | } catch (Exception $exception) { 128 | $this->logger->error(__('Cant complete webapi log save because of error: %1', $exception->getMessage())); 129 | } 130 | } 131 | 132 | /** 133 | * Check if request path is among the filters. 134 | * 135 | * @param string $requestPath 136 | * @param array $filters 137 | * 138 | * @return bool 139 | */ 140 | private function filterRequestPath( 141 | string $requestPath, 142 | array $filters 143 | ): bool { 144 | foreach ($filters as $filter) { 145 | if ($filter != '') { 146 | if (stripos($requestPath, $filter) !== false) { 147 | return true; 148 | } 149 | } 150 | } 151 | return false; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Model/ResourceModel/Entity/LogCollection.php: -------------------------------------------------------------------------------- 1 | _init(Log::class, LogResourceModel::class); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Model/ResourceModel/LogResourceModel.php: -------------------------------------------------------------------------------- 1 | _init('webapi_logs', 'log_id'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Model/SecretParser.php: -------------------------------------------------------------------------------- 1 | config = $config; 25 | } 26 | 27 | /** 28 | * @return string 29 | */ 30 | public function parseIp(): string 31 | { 32 | return '***.***.***.***'; 33 | } 34 | 35 | /** 36 | * @param string $header 37 | * @return string 38 | */ 39 | public function parseHeades(string $header): string 40 | { 41 | $secrets = $this->config->getSecrets(); 42 | $headers = implode('|', $secrets); 43 | return preg_replace('/('.$headers.'):(.*)/', '$1: ********', $header); 44 | } 45 | 46 | /** 47 | * @param string $body 48 | * @return string 49 | */ 50 | public function parseBody(string $body): string 51 | { 52 | $secrets = $this->config->getSecrets(); 53 | foreach ($secrets as $secret) { 54 | $body = preg_replace('/' . $secret . '(")*:( )*"(.*)"/', $secret . '$1: "********"', $body); 55 | } 56 | return $body; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Plugin/FrontControllerDispatchAfter.php: -------------------------------------------------------------------------------- 1 | config = $config; 45 | $this->date = $date; 46 | $this->logHandle = $logHandle; 47 | } 48 | 49 | /** 50 | * @param Rest $subject 51 | * @param $result 52 | * @param RequestInterface $request 53 | * @return mixed 54 | */ 55 | public function afterDispatch(Rest $subject, $result, RequestInterface $request) 56 | { 57 | if ($this->config->isEnabled() 58 | && ( 59 | !$request->isXmlHttpRequest() 60 | || !$this->config->isAjaxCallsDisabled() 61 | ) 62 | ) { 63 | $exceptions = $result->getException(); 64 | 65 | if (!empty($exceptions)) { 66 | $responseCode = ''; 67 | $resposeBody = ''; 68 | foreach ($exceptions as $exception) { 69 | $responseCode .= (string)$exception->getHttpCode() . ' '; 70 | $resposeBody .= $exception->getMessage() . ' '; 71 | } 72 | $responseCode = rtrim($responseCode); 73 | $resposeBody = rtrim($resposeBody); 74 | } else { 75 | $responseCode = (string)$result->getStatusCode(); 76 | $resposeBody = $result->getContent(); 77 | $resposeBody = trim($resposeBody, '"'); 78 | } 79 | 80 | $responseDateTime = $this->date->gmtDate(); 81 | $this->logHandle->after($responseCode, $resposeBody, $responseDateTime); 82 | } 83 | return $result; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Plugin/FrontControllerDispatchBefore.php: -------------------------------------------------------------------------------- 1 | config = $config; 45 | $this->date = $date; 46 | $this->logHandle = $logHandle; 47 | } 48 | 49 | /** 50 | * @param Rest $subject 51 | * @param RequestInterface $request 52 | * @return array 53 | */ 54 | public function beforeDispatch(Rest $subject, RequestInterface $request) 55 | { 56 | if ($this->config->isEnabled() 57 | && ( 58 | !$request->isXmlHttpRequest() 59 | || !$this->config->isAjaxCallsDisabled() 60 | ) 61 | ) { 62 | $requestMethod = $request->getMethod(); 63 | $requestorIp = $request->getClientIp(); 64 | $requestPath = $request->getUriString(); 65 | $requestHeaders = $request->getHeaders()->toString(); 66 | $requestBody = $request->getContent(); 67 | $requestDateTime = $this->date->gmtDate(); 68 | 69 | $this->logHandle->before( 70 | $requestMethod, 71 | $requestorIp, 72 | $requestPath, 73 | $requestHeaders, 74 | $requestBody, 75 | $requestDateTime 76 | ); 77 | } 78 | return [$request]; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | This module allows you to analyze all the webapi rest done call toward your magento. 4 | 5 | # Install 6 | 7 | `composer require youwe/module-webapi-logs` 8 | 9 | # Configure 10 | 11 | 1. Log-in your Magento backend 12 | 13 | 2. Go to `Stores > Configuration > System > Webapi Logs` and enable it 14 | 15 | 16 | 17 | # Use 18 | 19 | Go to `Reports > Webapi Logs > Show Logs` 20 | 21 | 22 | 23 | You can select an entry to see more details about the request and the response 24 | 25 | 26 | 27 | # Attention! 28 | 29 | If you disable the Secret Mode this module will logs everything passes in the webapi calls (tokens and passwords too!), then remember to clean logs by clicking the `Delete All Logs` button: 30 | 31 | 32 | 33 | # Contribution 34 | 35 | Yes, of course you can contribute sending a pull request to propose improvements and fixes. 36 | 37 | -------------------------------------------------------------------------------- /Ui/Component/Listing/Column/Datetime.php: -------------------------------------------------------------------------------- 1 | timezone = $timezone; 74 | $this->booleanUtils = $booleanUtils; 75 | $this->localeResolver = $localeResolver ?? ObjectManager::getInstance()->get(ResolverInterface::class); 76 | $this->locale = $this->localeResolver->getLocale(); 77 | $this->dataBundle = $dataBundle ?? ObjectManager::getInstance()->get(DataBundle::class); 78 | parent::__construct($context, $uiComponentFactory, $components, $data); 79 | } 80 | 81 | /** 82 | * @inheritdoc 83 | * @since 101.1.1 84 | */ 85 | public function prepare() 86 | { 87 | $config = $this->getData('config'); 88 | if (isset($config['filter'])) { 89 | $config['filter'] = [ 90 | 'filterType' => 'dateRange', 91 | 'templates' => [ 92 | 'date' => [ 93 | 'options' => [ 94 | 'dateFormat' => 'yyyy-MM-dd', 95 | 'showsTime' => true, 96 | 'timeFormat' => 'H:mm:ss', 97 | ] 98 | ] 99 | ] 100 | ]; 101 | } 102 | 103 | $localeData = $this->dataBundle->get($this->locale); 104 | /** @var ResourceBundle $monthsData */ 105 | $monthsData = $localeData['calendar']['gregorian']['monthNames']; 106 | $months = array_values(iterator_to_array($monthsData['format']['wide'])); 107 | $monthsShort = array_values( 108 | iterator_to_array( 109 | null !== $monthsData->get('format')->get('abbreviated') 110 | ? $monthsData['format']['abbreviated'] 111 | : $monthsData['format']['wide'] 112 | ) 113 | ); 114 | 115 | $config['storeLocale'] = $this->locale; 116 | $config['calendarConfig'] = [ 117 | 'months' => $months, 118 | 'monthsShort' => $monthsShort, 119 | ]; 120 | if (!isset($config['dateFormat'])) { 121 | $config['dateFormat'] = 'yyyy-MM-dd H:mm:ss'; 122 | } 123 | $config['options']['showsTime'] = true; 124 | $this->setData('config', $config); 125 | 126 | parent::prepare(); 127 | } 128 | 129 | /** 130 | * @inheritdoc 131 | */ 132 | public function prepareDataSource(array $dataSource) 133 | { 134 | if (isset($dataSource['data']['items'])) { 135 | foreach ($dataSource['data']['items'] as & $item) { 136 | if (isset($item[$this->getData('name')]) 137 | && $item[$this->getData('name')] !== "0000-00-00 00:00:00" 138 | ) { 139 | $date = $this->timezone->date(new \DateTime($item[$this->getData('name')])); 140 | $item[$this->getData('name')] = $date->format('Y-m-d H:i:s'); 141 | } 142 | } 143 | } 144 | 145 | return $dataSource; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /Ui/Component/Listing/Column/RowAction.php: -------------------------------------------------------------------------------- 1 | urlBuilder = $urlBuilder; 38 | parent::__construct($context, $uiComponentFactory, $components, $data); 39 | } 40 | 41 | /** 42 | * @param array $dataSource 43 | * @return array 44 | */ 45 | public function prepareDataSource(array $dataSource): array 46 | { 47 | if (isset($dataSource['data']['items'])) { 48 | foreach ($dataSource['data']['items'] as &$item) { 49 | $item[$this->getData('name')]['edit'] = [ 50 | 'href' => 51 | $this->urlBuilder->getUrl( 52 | 'webapi_logs/reports/detail', 53 | ['log_id' => $item['log_id']] 54 | ), 55 | 'label' => __('View More'), 56 | 'hidden' => false 57 | ]; 58 | } 59 | } 60 | 61 | return $dataSource; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Ui/DataProvider/LogListingDataProvider.php: -------------------------------------------------------------------------------- 1 | request = $request; 101 | $this->filterBuilder = $filterBuilder; 102 | $this->name = $name; 103 | $this->primaryFieldName = $primaryFieldName; 104 | $this->requestFieldName = $requestFieldName; 105 | $this->reporting = $reporting; 106 | $this->searchCriteriaBuilder = $searchCriteriaBuilder; 107 | $this->meta = $meta; 108 | $this->data = $data; 109 | $this->prepareUpdateUrl(); 110 | } 111 | 112 | /** 113 | * Get Data Provider name 114 | * 115 | * @return string 116 | */ 117 | public function getName(): string 118 | { 119 | return $this->name; 120 | } 121 | 122 | /** 123 | * Get primary field name 124 | * 125 | * @return string 126 | */ 127 | public function getPrimaryFieldName(): string 128 | { 129 | return $this->primaryFieldName; 130 | } 131 | 132 | /** 133 | * Get field name in request 134 | * 135 | * @return string 136 | */ 137 | public function getRequestFieldName(): string 138 | { 139 | return $this->requestFieldName; 140 | } 141 | 142 | /** 143 | * @return array 144 | */ 145 | public function getMeta(): array 146 | { 147 | return $this->meta; 148 | } 149 | 150 | /** 151 | * Get field Set meta info 152 | * 153 | * @param string $fieldSetName 154 | * @return array 155 | */ 156 | public function getFieldSetMetaInfo($fieldSetName): array 157 | { 158 | return $this->meta[$fieldSetName] ?? []; 159 | } 160 | 161 | /** 162 | * @param string $fieldSetName 163 | * @return array 164 | */ 165 | public function getFieldsMetaInfo($fieldSetName): array 166 | { 167 | return $this->meta[$fieldSetName]['children'] ?? []; 168 | } 169 | 170 | /** 171 | * @param string $fieldSetName 172 | * @param string $fieldName 173 | * @return array 174 | */ 175 | public function getFieldMetaInfo($fieldSetName, $fieldName): array 176 | { 177 | return $this->meta[$fieldSetName]['children'][$fieldName] ?? []; 178 | } 179 | 180 | /** 181 | * @inheritdoc 182 | */ 183 | public function addFilter(Filter $filter) 184 | { 185 | $this->searchCriteriaBuilder->addFilter($filter); 186 | } 187 | 188 | /** 189 | * self::setOrder() alias 190 | * 191 | * @param string $field 192 | * @param string $direction 193 | * @return void 194 | */ 195 | public function addOrder($field, $direction) 196 | { 197 | $this->searchCriteriaBuilder->addSortOrder($field, $direction); 198 | } 199 | 200 | /** 201 | * Set Query limit 202 | * 203 | * @param int $offset 204 | * @param int $size 205 | * @return void 206 | */ 207 | public function setLimit($offset, $size) 208 | { 209 | $this->searchCriteriaBuilder->setPageSize($size); 210 | $this->searchCriteriaBuilder->setCurrentPage($offset); 211 | } 212 | 213 | /** 214 | * @param SearchResultInterface $searchResult 215 | * @return array 216 | */ 217 | protected function searchResultToOutput(SearchResultInterface $searchResult): array 218 | { 219 | $arrItems = []; 220 | 221 | $arrItems['items'] = []; 222 | foreach ($searchResult->getItems() as $item) { 223 | $itemData = []; 224 | foreach ($item->getCustomAttributes() as $attribute) { 225 | $itemData[$attribute->getAttributeCode()] = $attribute->getValue(); 226 | } 227 | $arrItems['items'][] = $itemData; 228 | } 229 | 230 | $arrItems['totalRecords'] = $searchResult->getTotalCount(); 231 | 232 | return $arrItems; 233 | } 234 | 235 | /** 236 | * Returns search criteria 237 | * 238 | * @return SearchCriteria 239 | */ 240 | public function getSearchCriteria(): SearchCriteria 241 | { 242 | if (!isset($this->searchCriteria)) { 243 | $this->searchCriteria = $this->searchCriteriaBuilder->create(); 244 | $this->searchCriteria->setRequestName($this->name); 245 | } 246 | return $this->searchCriteria; 247 | } 248 | 249 | /** 250 | * Get data 251 | * 252 | * @return array 253 | */ 254 | public function getData(): array 255 | { 256 | return $this->searchResultToOutput($this->getSearchResult()); 257 | } 258 | 259 | /** 260 | * Get config data 261 | * 262 | * @return array 263 | */ 264 | public function getConfigData(): array 265 | { 266 | return $this->data['config'] ?? []; 267 | } 268 | 269 | /** 270 | * Set data 271 | * 272 | * @param mixed $config 273 | * @return void 274 | */ 275 | public function setConfigData($config) 276 | { 277 | $this->data['config'] = $config; 278 | } 279 | 280 | /** 281 | * Returns Search result 282 | * 283 | * @return SearchResultInterface 284 | */ 285 | public function getSearchResult(): SearchResultInterface 286 | { 287 | return $this->reporting->search($this->getSearchCriteria()); 288 | } 289 | 290 | protected function prepareUpdateUrl() 291 | { 292 | if (!isset($this->data['config']['filter_url_params'])) { 293 | return; 294 | } 295 | foreach ($this->data['config']['filter_url_params'] as $paramName => $paramValue) { 296 | if ('*' == $paramValue) { 297 | $paramValue = $this->request->getParam($paramName); 298 | } 299 | if ($paramValue) { 300 | $this->data['config']['update_url'] = sprintf( 301 | '%s%s/%s/', 302 | $this->data['config']['update_url'], 303 | $paramName, 304 | $paramValue 305 | ); 306 | $this->addFilter( 307 | $this->filterBuilder->setField($paramName)->setValue($paramValue)->setConditionType('eq')->create() 308 | ); 309 | } 310 | } 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /ViewModel/Detail.php: -------------------------------------------------------------------------------- 1 | logResourceModel = $logResourceModel; 47 | $this->logFactory = $logFactory; 48 | $this->request = $request; 49 | } 50 | 51 | public function getLog() 52 | { 53 | $logId = $this->request->getParam('log_id'); 54 | 55 | $log = $this->logFactory->create(); 56 | $this->logResourceModel->load($log, $logId); 57 | 58 | return $log; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "youwe/module-webapi-logs", 3 | "description": "Magento Webapi Log Details accessible via backend", 4 | "type": "magento2-module", 5 | "require": { 6 | "magento/framework": "*", 7 | "magento/module-webapi": "*" 8 | }, 9 | "authors": [ 10 | { 11 | "name": "Danilo Argentiero", 12 | "email": "argentiero.danilo@gmail.com", 13 | "homepage": "https://www.linkedin.com/in/daniloargentiero/", 14 | "role": "Software Architect" 15 | }, 16 | { 17 | "name": "Riccardo Ugolini", 18 | "email": "riccardo.ugolini@gmail.com", 19 | "homepage": "https://www.linkedin.com/in/riccardougolini/", 20 | "role": "Software Architect" 21 | } 22 | ], 23 | "license": [ 24 | "MIT" 25 | ], 26 | "autoload": { 27 | "files": [ 28 | "registration.php" 29 | ], 30 | "psr-4": { 31 | "GhostUnicorns\\WebapiLogs\\": "" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /etc/acl.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /etc/adminhtml/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 17 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 12 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 |
10 | separator-top 11 | 12 | advanced 13 | GhostUnicorns_WebapiLogs::reports 14 | 15 | 16 | 17 | 18 | Magento\Config\Model\Config\Source\Yesno 19 | 20 | 21 | 22 | 23 | Magento\Config\Model\Config\Source\Yesno 24 | 25 | 26 | 27 | Magento\Config\Model\Config\Source\Yesno 28 | 29 | 30 | 1 31 | 32 | 33 | 34 | 35 | 36 | 37 | 1 38 | 39 | 40 | 41 | 42 | 43 | 1 44 | 45 | validate-number validate-greater-than-zero 46 | 47 | 48 | 49 | 50 | 1 51 | 52 | 53 | 54 | 55 |
56 |
57 |
58 | -------------------------------------------------------------------------------- /etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 11 | 12 | 1 13 | 1 14 | Cookie 15 | User-Agent 16 | Authorization 17 | username 18 | password 19 | token 20 | email 21 | 24 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /etc/crontab.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 0 * * * * 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /etc/db_schema.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 | -------------------------------------------------------------------------------- /etc/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 11 | 12 | GhostUnicorns::WebapiLogs 13 | 14 | 15 | GhostUnicorns\WebapiLogs\Log\Handler 16 | 17 | 18 | 19 | 20 | 21 | 22 | /var/log/webapi_logs.log 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | GhostUnicorns\WebapiLogs\Console\Command\CleanCommand 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | GhostUnicorns\WebapiLogs\Model\ResourceModel\Logs\Grid\Collection\Virtual 55 | 56 | 57 | 58 | 59 | 60 | 62 | 63 | webapi_logs 64 | 65 | GhostUnicorns\WebapiLogs\Model\ResourceModel\LogResourceModel 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | GhostUnicorns\WebapiLogs\ViewModel\Detail 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /view/adminhtml/layout/webapi_logs_reports_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /view/adminhtml/templates/detail.phtml: -------------------------------------------------------------------------------- 1 | getViewModel(); 18 | 19 | $log = $viewModel->getLog(); 20 | ?> 21 | 22 |

Log id: getData('log_id') ?>

23 |
24 |

Request

25 |

requestor_ip:

26 |

getData('requestor_ip') ?>

27 |
28 |

request_url:

29 |

getData('request_url') ?>

30 |
31 |

request_method:

32 |

getData('request_method') ?>

33 |
34 |

request_body:

35 |

getData('request_body') ?>

36 |
37 |

request_headers:

38 |

getData('request_headers') ?>

39 |
40 |

Response

41 |

response_code:

42 |

getData('response_code') ?>

43 |
44 |

response_body:

45 |

getData('response_body') ?>

46 |
47 |

request_datetime:

48 |

getData('request_datetime') ?>

49 |
50 |

response_datetime:

51 |

getData('response_datetime') ?>

52 |
53 |

created_at:

54 |

getData('created_at') ?>

55 |
56 | 57 | 105 | -------------------------------------------------------------------------------- /view/adminhtml/ui_component/webapi_logs_reports_index_listing.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 8 | 9 | 10 | 11 | Delete All Logs 12 | primary 13 | webapi_logs/reports/delete 14 | 15 | 16 | 17 | 18 | webapi_logs_reports_index_listing.ghostunicorns_webapi_logs_entity_data_source 19 | 20 | 21 | webapi_logs_reports_index_listing.ghostunicorns_webapi_logs_entity_data_source 22 | 23 | 24 | spinner_columns 25 | 26 | 27 | 28 | 29 | \GhostUnicorns\WebapiLogs\Ui\DataProvider\LogListingDataProvider 30 | 31 | ghostunicorns_webapi_logs_entity_data_source 32 | log_id 33 | log_id 34 | 35 | 36 | Magento_Ui/js/grid/provider 37 | 38 | 39 | * 40 | 41 | 42 | log_id 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | true 51 | 52 | 53 | 54 | 55 | Magento_Ui/js/grid/controls/bookmarks/bookmarks 56 | dataGridActions 57 | 58 | 59 | 60 | webapi_logs_reports_index_listing 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | webapi_logs_reports_index_listing.webapi_logs_reports_index_listing.spinner_columns.ids 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | webapi_logs_reports_index_listing.webapi_logs_reports_index_listing.spinner_columns 82 | 83 | 84 | 85 | webapi_logs_reports_index_listing.webapi_logs_reports_index_listing.listing_top.bookmarks 86 | 87 | current.filters 88 | 89 | 90 | 91 | webapi_logs_reports_index_listing.webapi_logs_reports_index_listing.listing_top.listing_filters 92 | 93 | 94 | 95 | webapi_logs_reports_index_listing.webapi_logs_reports_index_listing.spinner_columns.${ $.index }:visible 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | true 108 | 109 | 110 | 111 | 112 | 113 | 114 | 20 115 | log_id 116 | 117 | 118 | 119 | 120 | 121 | 122 | 80 123 | text 124 | desc 125 | Log ID 126 | log_id 127 | 10 128 | 129 | 130 | 131 | 132 | 133 | GhostUnicorns\WebapiLogs\Model\Config\Source\Code 134 | 135 | 50 136 | select 137 | Response Code 138 | GhostUnicorns_WebapiLogs/js/grid/columns/select 139 | select 140 | select 141 | response_code 142 | 20 143 | 144 | 145 | 146 | 147 | 148 | GhostUnicorns\WebapiLogs\Model\Config\Source\Methods 149 | 150 | 50 151 | select 152 | Request Method 153 | Magento_Ui/js/grid/columns/select 154 | select 155 | select 156 | request_method 157 | 30 158 | 159 | 160 | 161 | 162 | 163 | 164 | text 165 | 200 166 | Request Url 167 | request_url 168 | 35 169 | 170 | 171 | 172 | 173 | 174 | GhostUnicorns\WebapiLogs\Model\Config\Source\RequestorIp 175 | 176 | select 177 | Requestor IP 178 | Magento_Ui/js/grid/columns/select 179 | select 180 | 100 181 | select 182 | requestor_ip 183 | 30 184 | 185 | 186 | 187 | 189 | 190 | dateRange 191 | date 192 | true 193 | true 194 | 100 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 60 204 | false 205 | log_id 206 | 207 | 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/grid/columns/select.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © Ghost Unicorns snc. All rights reserved. 3 | * See LICENSE for license details. 4 | */ 5 | 6 | define([ 7 | 'Magento_Ui/js/grid/columns/column' 8 | ], function ( 9 | Column 10 | ) { 11 | 'use strict'; 12 | 13 | return Column.extend({ 14 | defaults: { 15 | bodyTmpl: 'GhostUnicorns_WebapiLogs/ui/grid/cells/text' 16 | }, 17 | 18 | getStatusColor: function (row) { 19 | if (row.response_code == '200') { 20 | return '#90EE90'; 21 | } 22 | if (row.response_code == '500' || row.response_code == '400') { 23 | return '#ff7a7a'; 24 | } 25 | return '#ffd97a'; 26 | }, 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/js-beautify/beautify.min.js: -------------------------------------------------------------------------------- 1 | !function(){var u,n;function i(t){if(n[t])return n[t].exports;var e=n[t]={i:t,l:!1,exports:{}};return u[t].call(e.exports,e,e.exports,i),e.l=!0,e.exports}var t=(n={},i.m=u=[function(t,e,u){"use strict";var n=u(1).Beautifier,i=u(5).Options;t.exports=function(t,e){return new n(t,e).beautify()},t.exports.defaultOptions=function(){return new i}},function(t,e,u){"use strict";var n=u(2).Output,i=u(3).Token,o=u(4),_=u(5).Options,s=u(7).Tokenizer,r=u(7).line_starters,h=u(7).positionable_operators,p=u(7).TOKEN;function l(t,e){return-1!==e.indexOf(t)}function a(t,e){return t&&t.type===p.RESERVED&&t.text===e}function f(t,e){return t&&t.type===p.RESERVED&&l(t.text,e)}var c=["case","return","do","if","throw","else","await","break","continue","async"],d=function(t){for(var e={},u=0;uu&&(u=t.line_indent_level)),{mode:e,parent:t,last_token:t?t.last_token:new i(p.START_BLOCK,""),last_word:t?t.last_word:"",declaration_statement:!1,declaration_assignment:!1,multiline_frame:!1,inline_frame:!1,if_block:!1,else_block:!1,do_block:!1,do_while:!1,import_block:!1,in_case_statement:!1,in_case:!1,case_body:!1,indentation_level:u,alignment:0,line_indent_level:t?t.line_indent_level:u,start_line_index:this._output.get_line_number(),ternary_depth:0}},T.prototype._reset=function(t){var e=t.match(/^[\t ]*/)[0];this._last_last_text="",this._output=new n(this._options,e),this._output.raw=this._options.test_output_raw,this._flag_store=[],this.set_mode(g);e=new s(t,this._options);return this._tokens=e.tokenize(),t},T.prototype.beautify=function(){if(this._options.disabled)return this._source_text;var t=this._reset(this._source_text),e=this._options.eol;"auto"===this._options.eol&&(e="\n",t&&o.lineBreak.test(t||"")&&(e=t.match(o.lineBreak)[0]));for(var u=this._tokens.next();u;)this.handle_token(u),this._last_last_text=this._flags.last_token.text,this._flags.last_token=u,u=this._tokens.next();return this._output.get_code(e)},T.prototype.handle_token=function(t,e){t.type===p.START_EXPR?this.handle_start_expr(t):t.type===p.END_EXPR?this.handle_end_expr(t):t.type===p.START_BLOCK?this.handle_start_block(t):t.type===p.END_BLOCK?this.handle_end_block(t):t.type===p.WORD||t.type===p.RESERVED?this.handle_word(t):t.type===p.SEMICOLON?this.handle_semicolon(t):t.type===p.STRING?this.handle_string(t):t.type===p.EQUALS?this.handle_equals(t):t.type===p.OPERATOR?this.handle_operator(t):t.type===p.COMMA?this.handle_comma(t):t.type===p.BLOCK_COMMENT?this.handle_block_comment(t,e):t.type===p.COMMENT?this.handle_comment(t,e):t.type===p.DOT?this.handle_dot(t):t.type===p.EOF?this.handle_eof(t):(t.type,p.UNKNOWN,this.handle_unknown(t,e))},T.prototype.handle_whitespace_and_comments=function(t,e){var u=t.newlines,n=this._options.keep_array_indentation&&O(this._flags.mode);if(t.comments_before)for(var i=t.comments_before.next();i;)this.handle_whitespace_and_comments(i,e),this.handle_token(i,e),i=t.comments_before.next();if(n)for(var _=0;_this._options.max_preserve_newlines&&(u=this._options.max_preserve_newlines),this._options.preserve_newlines&&1this._flags.parent.indentation_level)&&(--this._flags.indentation_level,this._output.set_indent(this._flags.indentation_level,this._flags.alignment))},T.prototype.set_mode=function(t){this._flags?(this._flag_store.push(this._flags),this._previous_flags=this._flags):this._previous_flags=this.create_flags(null,t),this._flags=this.create_flags(this._previous_flags,t),this._output.set_indent(this._flags.indentation_level,this._flags.alignment)},T.prototype.restore_mode=function(){0"!==this._flags.last_token.text)&&(l(this._flags.last_token.type,[p.EQUALS,p.START_EXPR,p.COMMA,p.OPERATOR])||f(this._flags.last_token,["return","throw","import","default"]))?this.set_mode(k):this.set_mode(g);u=!e.comments_before&&"}"===e.text,e=u&&"function"===this._flags.last_word&&this._flags.last_token.type===p.END_EXPR;if(this._options.brace_preserve_inline){var n=0,i=null;this._flags.inline_frame=!0;do{if(n+=1,(i=this._tokens.peek(n-1)).newlines){this._flags.inline_frame=!1;break}}while(i.type!==p.EOF&&(i.type!==p.END_BLOCK||i.opened!==t))}("expand"===this._options.brace_style||"none"===this._options.brace_style&&t.newlines)&&!this._flags.inline_frame?this._flags.last_token.type!==p.OPERATOR&&(e||this._flags.last_token.type===p.EQUALS||f(this._flags.last_token,c)&&"else"!==this._flags.last_token.text)?this._output.space_before_token=!0:this.print_newline(!1,!0):(!O(this._previous_flags.mode)||this._flags.last_token.type!==p.START_EXPR&&this._flags.last_token.type!==p.COMMA||(this._flags.last_token.type!==p.COMMA&&!this._options.space_in_paren||(this._output.space_before_token=!0),(this._flags.last_token.type===p.COMMA||this._flags.last_token.type===p.START_EXPR&&this._flags.inline_frame)&&(this.allow_wrap_or_preserved_newline(t),this._previous_flags.multiline_frame=this._previous_flags.multiline_frame||this._flags.multiline_frame,this._flags.multiline_frame=!1)),this._flags.last_token.type!==p.OPERATOR&&this._flags.last_token.type!==p.START_EXPR&&(this._flags.last_token.type!==p.START_BLOCK||this._flags.inline_frame?this._output.space_before_token=!0:this.print_newline())),this.print_token(t),this.indent(),u||this._options.brace_preserve_inline&&this._flags.inline_frame||this.print_newline()},T.prototype.handle_end_block=function(t){for(this.handle_whitespace_and_comments(t);this._flags.mode===m;)this.restore_mode();var e=this._flags.last_token.type===p.START_BLOCK;this._flags.inline_frame&&!e?this._output.space_before_token=!0:"expand"===this._options.brace_style?e||this.print_newline():e||(O(this._flags.mode)&&this._options.keep_array_indentation?(this._options.keep_array_indentation=!1,this.print_newline(),this._options.keep_array_indentation=!0):this.print_newline()),this.restore_mode(),this.print_token(t)},T.prototype.handle_word=function(t){if(t.type===p.RESERVED&&(l(t.text,["set","get"])&&this._flags.mode!==k||"import"===t.text&&"("===this._tokens.peek().text||l(t.text,["as","from"])&&!this._flags.import_block||this._flags.mode===k&&":"===this._tokens.peek().text)&&(t.type=p.WORD),this.start_of_statement(t)?f(this._flags.last_token,["var","let","const"])&&t.type===p.WORD&&(this._flags.declaration_statement=!0):!t.newlines||R(this._flags.mode)||this._flags.last_token.type===p.OPERATOR&&"--"!==this._flags.last_token.text&&"++"!==this._flags.last_token.text||this._flags.last_token.type===p.EQUALS||!this._options.preserve_newlines&&f(this._flags.last_token,["var","let","const","set","get"])?this.handle_whitespace_and_comments(t):(this.handle_whitespace_and_comments(t),this.print_newline()),this._flags.do_block&&!this._flags.do_while){if(a(t,"while"))return this._output.space_before_token=!0,this.print_token(t),this._output.space_before_token=!0,void(this._flags.do_while=!0);this.print_newline(),this._flags.do_block=!1}if(this._flags.if_block)if(!this._flags.else_block&&a(t,"else"))this._flags.else_block=!0;else{for(;this._flags.mode===m;)this.restore_mode();this._flags.if_block=!1,this._flags.else_block=!1}if(this._flags.in_case_statement&&f(t,["case","default"]))return this.print_newline(),this._flags.last_token.type!==p.END_BLOCK&&(this._flags.case_body||this._options.jslint_happy)&&this.deindent(),this._flags.case_body=!1,this.print_token(t),void(this._flags.in_case=!0);if(this._flags.last_token.type!==p.COMMA&&this._flags.last_token.type!==p.START_EXPR&&this._flags.last_token.type!==p.EQUALS&&this._flags.last_token.type!==p.OPERATOR||this.start_of_object_property()||this.allow_wrap_or_preserved_newline(t),a(t,"function"))return(l(this._flags.last_token.text,["}",";"])||this._output.just_added_newline()&&!l(this._flags.last_token.text,["(","[","{",":","=",","])&&this._flags.last_token.type!==p.OPERATOR)&&(this._output.just_added_blankline()||t.comments_before||(this.print_newline(),this.print_newline(!0))),this._flags.last_token.type===p.RESERVED||this._flags.last_token.type===p.WORD?f(this._flags.last_token,["get","set","new","export"])||f(this._flags.last_token,A)||a(this._flags.last_token,"default")&&"export"===this._last_last_text||"declare"===this._flags.last_token.text?this._output.space_before_token=!0:this.print_newline():this._flags.last_token.type===p.OPERATOR||"="===this._flags.last_token.text?this._output.space_before_token=!0:!this._flags.multiline_frame&&(R(this._flags.mode)||O(this._flags.mode))||this.print_newline(),this.print_token(t),void(this._flags.last_word=t.text);var e="NONE";this._flags.last_token.type===p.END_BLOCK?this._previous_flags.inline_frame?e="SPACE":!f(t,["else","catch","finally","from"])||"expand"===this._options.brace_style||"end-expand"===this._options.brace_style||"none"===this._options.brace_style&&t.newlines?e="NEWLINE":(e="SPACE",this._output.space_before_token=!0):this._flags.last_token.type===p.SEMICOLON&&this._flags.mode===g?e="NEWLINE":this._flags.last_token.type===p.SEMICOLON&&R(this._flags.mode)?e="SPACE":this._flags.last_token.type===p.STRING?e="NEWLINE":this._flags.last_token.type===p.RESERVED||this._flags.last_token.type===p.WORD||"*"===this._flags.last_token.text&&(l(this._last_last_text,["function","yield"])||this._flags.mode===k&&l(this._last_last_text,["{",","]))?e="SPACE":this._flags.last_token.type===p.START_BLOCK?e=this._flags.inline_frame?"SPACE":"NEWLINE":this._flags.last_token.type===p.END_EXPR&&(this._output.space_before_token=!0,e="NEWLINE"),f(t,r)&&")"!==this._flags.last_token.text&&(e=this._flags.inline_frame||"else"===this._flags.last_token.text||"export"===this._flags.last_token.text?"SPACE":"NEWLINE"),f(t,["else","catch","finally"])?(this._flags.last_token.type!==p.END_BLOCK||this._previous_flags.mode!==g||"expand"===this._options.brace_style||"end-expand"===this._options.brace_style||"none"===this._options.brace_style&&t.newlines)&&!this._flags.inline_frame?this.print_newline():(this._output.trim(!0),"}"!==this._output.current_line.last()&&this.print_newline(),this._output.space_before_token=!0):"NEWLINE"===e?f(this._flags.last_token,c)||"declare"===this._flags.last_token.text&&f(t,["var","let","const"])?this._output.space_before_token=!0:this._flags.last_token.type!==p.END_EXPR?this._flags.last_token.type===p.START_EXPR&&f(t,["var","let","const"])||":"===this._flags.last_token.text||(a(t,"if")&&a(t.previous,"else")?this._output.space_before_token=!0:this.print_newline()):f(t,r)&&")"!==this._flags.last_token.text&&this.print_newline():this._flags.multiline_frame&&O(this._flags.mode)&&","===this._flags.last_token.text&&"}"===this._last_last_text?this.print_newline():"SPACE"===e&&(this._output.space_before_token=!0),!t.previous||t.previous.type!==p.WORD&&t.previous.type!==p.RESERVED||(this._output.space_before_token=!0),this.print_token(t),this._flags.last_word=t.text,t.type===p.RESERVED&&("do"===t.text?this._flags.do_block=!0:"if"===t.text?this._flags.if_block=!0:"import"===t.text?this._flags.import_block=!0:this._flags.import_block&&a(t,"from")&&(this._flags.import_block=!1))},T.prototype.handle_semicolon=function(t){this.start_of_statement(t)?this._output.space_before_token=!1:this.handle_whitespace_and_comments(t);for(var e=this._tokens.peek();!(this._flags.mode!==m||this._flags.if_block&&a(e,"else")||this._flags.do_block);)this.restore_mode();this._flags.import_block&&(this._flags.import_block=!1),this.print_token(t)},T.prototype.handle_string=function(t){t.text.startsWith("`")&&0===t.newlines&&""===t.whitespace_before&&(")"===t.previous.text||this._flags.last_token.type===p.WORD)||(this.start_of_statement(t)?this._output.space_before_token=!0:(this.handle_whitespace_and_comments(t),this._flags.last_token.type===p.RESERVED||this._flags.last_token.type===p.WORD||this._flags.inline_frame?this._output.space_before_token=!0:this._flags.last_token.type===p.COMMA||this._flags.last_token.type===p.START_EXPR||this._flags.last_token.type===p.EQUALS||this._flags.last_token.type===p.OPERATOR?this.start_of_object_property()||this.allow_wrap_or_preserved_newline(t):!t.text.startsWith("`")||this._flags.last_token.type!==p.END_EXPR||"]"!==t.previous.text&&")"!==t.previous.text||0!==t.newlines?this.print_newline():this._output.space_before_token=!0)),this.print_token(t)},T.prototype.handle_equals=function(t){this.start_of_statement(t)||this.handle_whitespace_and_comments(t),this._flags.declaration_statement&&(this._flags.declaration_assignment=!0),this._output.space_before_token=!0,this.print_token(t),this._output.space_before_token=!0},T.prototype.handle_comma=function(t){this.handle_whitespace_and_comments(t,!0),this.print_token(t),this._output.space_before_token=!0,this._flags.declaration_statement?(R(this._flags.parent.mode)&&(this._flags.declaration_assignment=!1),this._flags.declaration_assignment?(this._flags.declaration_assignment=!1,this.print_newline(!1,!0)):this._options.comma_first&&this.allow_wrap_or_preserved_newline(t)):this._flags.mode===k||this._flags.mode===m&&this._flags.parent.mode===k?(this._flags.mode===m&&this.restore_mode(),this._flags.inline_frame||this.print_newline()):this._options.comma_first&&this.allow_wrap_or_preserved_newline(t)},T.prototype.handle_operator=function(t){var e="*"===t.text&&(f(this._flags.last_token,["function","yield"])||l(this._flags.last_token.type,[p.START_BLOCK,p.COMMA,p.END_BLOCK,p.SEMICOLON])),u=l(t.text,["-","+"])&&(l(this._flags.last_token.type,[p.START_BLOCK,p.START_EXPR,p.EQUALS,p.OPERATOR])||l(this._flags.last_token.text,r)||","===this._flags.last_token.text);if(this.start_of_statement(t)||(a=!e,this.handle_whitespace_and_comments(t,a)),f(this._flags.last_token,c))return this._output.space_before_token=!0,void this.print_token(t);if("*"!==t.text||this._flags.last_token.type!==p.DOT)if("::"!==t.text){if(this._flags.last_token.type===p.OPERATOR&&l(this._options.operator_position,b)&&this.allow_wrap_or_preserved_newline(t),":"===t.text&&this._flags.in_case)return this.print_token(t),this._flags.in_case=!1,this._flags.case_body=!0,void(this._tokens.peek().type!==p.START_BLOCK?(this.indent(),this.print_newline()):this._output.space_before_token=!0);var n=!0,i=!0,_=!1;if(":"===t.text?0===this._flags.ternary_depth?n=!1:(--this._flags.ternary_depth,_=!0):"?"===t.text&&(this._flags.ternary_depth+=1),!u&&!e&&this._options.preserve_newlines&&l(t.text,h)){var s=":"===t.text,a=s&&_,_=s&&!_;switch(this._options.operator_position){case d.before_newline:return this._output.space_before_token=!_,this.print_token(t),s&&!a||this.allow_wrap_or_preserved_newline(t),void(this._output.space_before_token=!0);case d.after_newline:return this._output.space_before_token=!0,!s||a?this._tokens.peek().newlines?this.print_newline(!1,!0):this.allow_wrap_or_preserved_newline(t):this._output.space_before_token=!1,this.print_token(t),void(this._output.space_before_token=!0);case d.preserve_newline:return _||this.allow_wrap_or_preserved_newline(t),n=!(this._output.just_added_newline()||_),this._output.space_before_token=n,this.print_token(t),void(this._output.space_before_token=!0)}}e?(this.allow_wrap_or_preserved_newline(t),n=!1,i=(e=this._tokens.peek())&&l(e.type,[p.WORD,p.RESERVED])):"..."===t.text?(this.allow_wrap_or_preserved_newline(t),n=this._flags.last_token.type===p.START_BLOCK,i=!1):(l(t.text,["--","++","!","~"])||u)&&(this._flags.last_token.type!==p.COMMA&&this._flags.last_token.type!==p.START_EXPR||this.allow_wrap_or_preserved_newline(t),i=n=!1,!t.newlines||"--"!==t.text&&"++"!==t.text||this.print_newline(!1,!0),";"===this._flags.last_token.text&&R(this._flags.mode)&&(n=!0),this._flags.last_token.type===p.RESERVED?n=!0:this._flags.last_token.type===p.END_EXPR?n=!("]"===this._flags.last_token.text&&("--"===t.text||"++"===t.text)):this._flags.last_token.type===p.OPERATOR&&(n=l(t.text,["--","-","++","+"])&&l(this._flags.last_token.text,["--","-","++","+"]),l(t.text,["+","-"])&&l(this._flags.last_token.text,["--","++"])&&(i=!0)),(this._flags.mode!==g||this._flags.inline_frame)&&this._flags.mode!==m||"{"!==this._flags.last_token.text&&";"!==this._flags.last_token.text||this.print_newline()),this._output.space_before_token=this._output.space_before_token||n,this.print_token(t),this._output.space_before_token=i}else this.print_token(t);else this.print_token(t)},T.prototype.handle_block_comment=function(t,e){return this._output.raw?(this._output.add_raw_token(t),void(t.directives&&"end"===t.directives.preserve&&(this._output.raw=this._options.test_output_raw))):t.directives?(this.print_newline(!1,e),this.print_token(t),"start"===t.directives.preserve&&(this._output.raw=!0),void this.print_newline(!1,!0)):void(o.newline.test(t.text)||t.newlines?this.print_block_commment(t,e):(this._output.space_before_token=!0,this.print_token(t),this._output.space_before_token=!0))},T.prototype.print_block_commment=function(t,e){var u,n,i,_=function(t){for(var e=[],u=(t=t.replace(o.allLineBreaks,"\n")).indexOf("\n");-1!==u;)e.push(t.substring(0,u)),u=(t=t.substring(u+1)).indexOf("\n");return t.length&&e.push(t),e}(t.text),s=t.whitespace_before,a=s.length;if(this.print_newline(!1,e),this.print_token_line_indentation(t),this._output.add_token(_[0]),this.print_newline(!1,e),1<_.length){for(n=function(t,e){for(var u=0;uthis.__parent.wrap_line_length&&this.__wrap_point_character_count>this.__parent.next_line.__character_count},i.prototype._allow_wrap=function(){if(this._should_wrap()){this.__parent.add_new_line();var t=this.__parent.current_line;return t.set_indent(this.__wrap_point_indent_count,this.__wrap_point_alignment_count),t.__items=this.__items.slice(this.__wrap_point_index),this.__items=this.__items.slice(0,this.__wrap_point_index),t.__character_count+=this.__character_count-this.__wrap_point_character_count,this.__character_count=this.__wrap_point_character_count," "===t.__items[0]&&(t.__items.splice(0,1),--t.__character_count),!0}return!1},i.prototype.is_empty=function(){return 0===this.__items.length},i.prototype.last=function(){return this.is_empty()?null:this.__items[this.__items.length-1]},i.prototype.push=function(t){this.__items.push(t);var e=t.lastIndexOf("\n");-1!==e?this.__character_count=t.length-e:this.__character_count+=t.length},i.prototype.pop=function(){var t=null;return this.is_empty()||(t=this.__items.pop(),this.__character_count-=t.length),t},i.prototype._remove_indent=function(){0=this.__cache.length;)this.__add_column()},n.prototype.__add_column=function(){var t,e=this.__cache.length,u="";this.__indent_size&&e>=this.__indent_size&&(e-=(t=Math.floor(e/this.__indent_size))*this.__indent_size,u=new Array(t+1).join(this.__indent_string)),e&&(u+=new Array(e+1).join(" ")),this.__cache.push(u)},_.prototype.__add_outputline=function(){this.previous_line=this.current_line,this.current_line=this.next_line.clone_empty(),this.__lines.push(this.current_line)},_.prototype.get_line_number=function(){return this.__lines.length},_.prototype.get_indent_string=function(t,e){return this.__indent_cache.get_indent_string(t,e)},_.prototype.get_indent_size=function(t,e){return this.__indent_cache.get_indent_size(t,e)},_.prototype.is_empty=function(){return!this.previous_line&&this.current_line.is_empty()},_.prototype.add_new_line=function(t){return!(this.is_empty()||!t&&this.just_added_newline())&&(this.raw||this.__add_outputline(),!0)},_.prototype.get_code=function(t){this.trim(!0);var e=this.current_line.pop();e&&("\n"===e[e.length-1]&&(e=e.replace(/\n+$/g,"")),this.current_line.push(e)),this._end_with_newline&&this.__add_outputline();e=this.__lines.join("\n");return"\n"!==t&&(e=e.replace(/[\n]/g,t)),e},_.prototype.set_wrap_point=function(){this.current_line._set_wrap_point()},_.prototype.set_indent=function(t,e){return t=t||0,e=e||0,this.next_line.set_indent(t,e),1>> === !== << && >= ** != == <= >> || ?? |> < / - + > : & % ? ^ | *".split(" "),i=">>>= ... >>= <<= === >>> !== **= => ^= :: /= << <= == && -= >= >> != -- += ** || ?? ++ %= &= *= |= |> = ! ? > < : / ^ - + * & % ~ |";i=(i="\\?\\.(?!\\d) "+(i=i.replace(/[-[\]{}()*+?.,\\^$|#]/g,"\\$&"))).replace(/ /g,"|");var b,g=new RegExp(i),s="continue,try,throw,return,var,let,const,if,switch,case,default,for,while,break,function,import,export".split(","),i=s.concat(["do","in","of","else","get","set","new","catch","finally","typeof","yield","async","await","from","as"]),m=new RegExp("^(?:"+i.join("|")+")$"),i=function(t,e){n.call(this,t,e),this._patterns.whitespace=this._patterns.whitespace.matching(/\u00A0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff/.source,/\u2028\u2029/.source);t=new a(this._input),e=new o(this._input).read_options(this._options);this.__patterns={template:e,identifier:e.starting_with(r.identifier).matching(r.identifierMatch),number:t.matching(f),punct:t.matching(g),comment:t.starting_with(/\/\//).until(/[\n\r\u2028\u2029]/),block_comment:t.starting_with(/\/\*/).until_after(/\*\//),html_comment_start:t.matching(//),include:t.starting_with(/#include/).until_after(r.lineBreak),shebang:t.starting_with(/#!/).until_after(r.lineBreak),xml:t.matching(/[\s\S]*?<(\/?)([-a-zA-Z:0-9_.]+|{[\s\S]+?}|!\[CDATA\[[\s\S]*?\]\]|)(\s+{[\s\S]+?}|\s+[-a-zA-Z:0-9_.]+|\s+[-a-zA-Z:0-9_.]+\s*=\s*('[^']*'|"[^"]*"|{[\s\S]+?}))*\s*(\/?)\s*>/),single_quote:e.until(/['\\\n\r\u2028\u2029]/),double_quote:e.until(/["\\\n\r\u2028\u2029]/),template_text:e.until(/[`\\$]/),template_expression:e.until(/[`}\\]/)}};(i.prototype=new n)._is_comment=function(t){return t.type===p.COMMENT||t.type===p.BLOCK_COMMENT||t.type===p.UNKNOWN},i.prototype._is_opening=function(t){return t.type===p.START_BLOCK||t.type===p.START_EXPR},i.prototype._is_closing=function(t,e){return(t.type===p.END_BLOCK||t.type===p.END_EXPR)&&e&&("]"===t.text&&"["===e.text||")"===t.text&&"("===e.text||"}"===t.text&&"{"===e.text)},i.prototype._reset=function(){b=!1},i.prototype._get_next_token=function(t,e){this._readWhitespace();var u=this._input.peek();return null===u?this._create_token(p.EOF,""):this._read_non_javascript(u)||this._read_string(u)||this._read_word(t)||this._read_singles(u)||this._read_comment(u)||this._read_regexp(u,t)||this._read_xml(u,t)||this._read_punctuation()||this._create_token(p.UNKNOWN,this._input.next())},i.prototype._read_word=function(t){var e=this.__patterns.identifier.read();return""!==e?(e=e.replace(r.allLineBreaks,"\n"),t.type!==p.DOT&&(t.type!==p.RESERVED||"set"!==t.text&&"get"!==t.text)&&m.test(e)?"in"===e||"of"===e?this._create_token(p.OPERATOR,e):this._create_token(p.RESERVED,e):this._create_token(p.WORD,e)):""!==(e=this.__patterns.number.read())?this._create_token(p.WORD,e):void 0},i.prototype._read_singles=function(t){var e=null;return"("===t||"["===t?e=this._create_token(p.START_EXPR,t):")"===t||"]"===t?e=this._create_token(p.END_EXPR,t):"{"===t?e=this._create_token(p.START_BLOCK,t):"}"===t?e=this._create_token(p.END_BLOCK,t):";"===t?e=this._create_token(p.SEMICOLON,t):"."===t&&d.test(this._input.peek(1))?e=this._create_token(p.DOT,t):","===t&&(e=this._create_token(p.COMMA,t)),e&&this._input.next(),e},i.prototype._read_punctuation=function(){var t=this.__patterns.punct.read();if(""!==t)return"="===t?this._create_token(p.EQUALS,t):"?."===t?this._create_token(p.DOT,t):this._create_token(p.OPERATOR,t)},i.prototype._read_non_javascript=function(t){var e="";if("#"===t){if(this._is_first_token()&&(e=this.__patterns.shebang.read()))return this._create_token(p.UNKNOWN,e.trim()+"\n");if(e=this.__patterns.include.read())return this._create_token(p.UNKNOWN,e.trim()+"\n");t=this._input.next();var u="#";if(this._input.hasNext()&&this._input.testChar(c)){for(;u+=t=this._input.next(),this._input.hasNext()&&"#"!==t&&"="!==t;);return"#"===t||("["===this._input.peek()&&"]"===this._input.peek(1)?(u+="[]",this._input.next(),this._input.next()):"{"===this._input.peek()&&"}"===this._input.peek(1)&&(u+="{}",this._input.next(),this._input.next())),this._create_token(p.WORD,u)}this._input.back()}else if("<"===t&&this._is_first_token()){if(e=this.__patterns.html_comment_start.read()){for(;this._input.hasNext()&&!this._input.testChar(r.newline);)e+=this._input.next();return b=!0,this._create_token(p.COMMENT,e)}}else if(b&&"-"===t&&(e=this.__patterns.html_comment_end.read()))return b=!1,this._create_token(p.COMMENT,e);return null},i.prototype._read_comment=function(t){var e,u=null;return"/"===t&&(e="","*"===this._input.peek(1)?(e=this.__patterns.block_comment.read(),(t=l.get_directives(e))&&"start"===t.ignore&&(e+=l.readIgnored(this._input)),e=e.replace(r.allLineBreaks,"\n"),(u=this._create_token(p.BLOCK_COMMENT,e)).directives=t):"/"===this._input.peek(1)&&(e=this.__patterns.comment.read(),u=this._create_token(p.COMMENT,e))),u},i.prototype._read_string=function(t){if("`"!==t&&"'"!==t&&'"'!==t)return null;var e=this._input.next();return this.has_char_escapes=!1,e+="`"===t?this._read_string_recursive("`",!0,"${"):this._read_string_recursive(t),this.has_char_escapes&&this._options.unescape_strings&&(e=function(t){var e="",u=0,n=new _(t),i=null;for(;n.hasNext();)if((i=n.match(/([\s]|[^\\]|\\\\)+/g))&&(e+=i[0]),"\\"===n.peek()){if(n.next(),"x"===n.peek())i=n.match(/x([0-9A-Fa-f]{2})/g);else{if("u"!==n.peek()){e+="\\",n.hasNext()&&(e+=n.next());continue}i=n.match(/u([0-9A-Fa-f]{4})/g)}if(!i)return t;if(126<(u=parseInt(i[1],16))&&u<=255&&0===i[0].indexOf("x"))return t;e+=0<=u&&u<32?"\\"+i[0]:34===u||39===u||92===u?"\\"+String.fromCharCode(u):String.fromCharCode(u)}return e}(e)),this._input.peek()===t&&(e+=this._input.next()),e=e.replace(r.allLineBreaks,"\n"),this._create_token(p.STRING,e)},i.prototype._allow_regexp_or_xml=function(t){return t.type===p.RESERVED&&h(t.text,["return","case","throw","else","do","typeof","yield"])||t.type===p.END_EXPR&&")"===t.text&&t.opened.previous.type===p.RESERVED&&h(t.opened.previous.text,["if","while","for"])||h(t.type,[p.COMMENT,p.START_EXPR,p.START_BLOCK,p.START,p.END_BLOCK,p.OPERATOR,p.EQUALS,p.EOF,p.SEMICOLON,p.COMMA])},i.prototype._read_regexp=function(t,e){if("/"===t&&this._allow_regexp_or_xml(e)){for(var u=this._input.next(),n=!1,i=!1;this._input.hasNext()&&(n||i||this._input.peek()!==t)&&!this._input.testChar(r.newline);)u+=this._input.peek(),n?n=!1:(n="\\"===this._input.peek(),"["===this._input.peek()?i=!0:"]"===this._input.peek()&&(i=!1)),this._input.next();return this._input.peek()===t&&(u+=this._input.next(),u+=this._input.read(r.identifier)),this._create_token(p.STRING,u)}return null},i.prototype._read_xml=function(t,e){if(this._options.e4x&&"<"===t&&this._allow_regexp_or_xml(e)){var u="",n=this.__patterns.xml.read_match();if(n){for(var i=n[2].replace(/^{\s+/,"{").replace(/\s+}$/,"}"),_=0===i.indexOf("{"),s=0;n;){var a=!!n[1],o=n[2];if(!(!!n[n.length-1]||"![CDATA["===o.slice(0,8))&&(o===i||_&&o.replace(/^{\s+/,"{").replace(/\s+}$/,"}"))&&(a?--s:++s),u+=n[0],s<=0)break;n=this.__patterns.xml.read_match()}return n||(u+=this._input.match(/[\s\S]*/g)[0]),u=u.replace(r.allLineBreaks,"\n"),this._create_token(p.STRING,u)}}return null},i.prototype._read_string_recursive=function(t,e,u){var n,i;"'"===t?i=this.__patterns.single_quote:'"'===t?i=this.__patterns.double_quote:"`"===t?i=this.__patterns.template_text:"}"===t&&(i=this.__patterns.template_expression);for(var _=i.read(),s="";this._input.hasNext();){if((s=this._input.next())===t||!e&&r.newline.test(s)){this._input.back();break}"\\"===s&&this._input.hasNext()?("x"===(n=this._input.peek())||"u"===n?this.has_char_escapes=!0:"\r"===n&&"\n"===this._input.peek(1)&&this._input.next(),s+=this._input.next()):u&&("${"===u&&"$"===s&&"{"===this._input.peek()&&(s+=this._input.next()),u===s&&(s+="`"===t?this._read_string_recursive("}",e,"`"):this._read_string_recursive("`",e,"${"),this._input.hasNext()&&(s+=this._input.next()))),_+=s+=i.read()}return _},t.exports.Tokenizer=i,t.exports.TOKEN=p,t.exports.positionable_operators=u.slice(),t.exports.line_starters=s.slice()},function(t,e,u){"use strict";var n=RegExp.prototype.hasOwnProperty("sticky");function i(t){this.__input=t||"",this.__input_length=this.__input.length,this.__position=0}i.prototype.restart=function(){this.__position=0},i.prototype.back=function(){0=t.length&&this.__input.substring(e-t.length,e).toLowerCase()===t},t.exports.InputScanner=i},function(t,e,u){"use strict";var n=u(8).InputScanner,_=u(3).Token,s=u(10).TokenStream,i=u(11).WhitespacePattern,a={START:"TK_START",RAW:"TK_RAW",EOF:"TK_EOF"},u=function(t,e){this._input=new n(t),this._options=e||{},this.__tokens=null,this._patterns={},this._patterns.whitespace=new i(this._input)};u.prototype.tokenize=function(){var t;this._input.restart(),this.__tokens=new s,this._reset();for(var e=new _(a.START,""),u=null,n=[],i=new s;e.type!==a.EOF;){for(t=this._get_next_token(e,u);this._is_comment(t);)i.add(t),t=this._get_next_token(e,u);i.isEmpty()||(t.comments_before=i,i=new s),t.parent=u,this._is_opening(t)?(n.push(u),u=t):u&&this._is_closing(t,u)&&((t.opened=u).closed=t,u=n.pop(),t.parent=u),(t.previous=e).next=t,this.__tokens.add(t),e=t}return this.__tokens},u.prototype._is_first_token=function(){return this.__tokens.isEmpty()},u.prototype._reset=function(){},u.prototype._get_next_token=function(t,e){this._readWhitespace();var u=this._input.read(/.+/g);return u?this._create_token(a.RAW,u):this._create_token(a.EOF,"")},u.prototype._is_comment=function(t){return!1},u.prototype._is_opening=function(t){return!1},u.prototype._is_closing=function(t,e){return!1},u.prototype._create_token=function(t,e){return new _(t,e,this._patterns.whitespace.newline_count,this._patterns.whitespace.whitespace_before_token)},u.prototype._readWhitespace=function(){return this._patterns.whitespace.read()},t.exports.Tokenizer=u,t.exports.TOKEN=a},function(t,e,u){"use strict";function n(t){this.__tokens=[],this.__tokens_length=this.__tokens.length,this.__position=0,this.__parent_token=t}n.prototype.restart=function(){this.__position=0},n.prototype.isEmpty=function(){return 0===this.__tokens_length},n.prototype.hasNext=function(){return this.__position/),erb:t.starting_with(/<%[^%]/).until_after(/[^%]%>/),django:t.starting_with(/{%/).until_after(/%}/),django_value:t.starting_with(/{{/).until_after(/}}/),django_comment:t.starting_with(/{#/).until_after(/#}/),smarty:t.starting_with(/{(?=[^}{\s\n])/).until_after(/[^\s\n]}/),smarty_comment:t.starting_with(/{\*/).until_after(/\*}/),smarty_literal:t.starting_with(/{literal}/).until_after(/{\/literal}/)}}(_.prototype=new n)._create=function(){return new _(this._input,this)},_.prototype._update=function(){this.__set_templated_pattern()},_.prototype.disable=function(t){var e=this._create();return e._disabled[t]=!0,e._update(),e},_.prototype.read_options=function(t){var e,u=this._create();for(e in i)u._disabled[e]=-1===t.templating.indexOf(e);return u._update(),u},_.prototype.exclude=function(t){var e=this._create();return e._excluded[t]=!0,e._update(),e},_.prototype.read=function(){for(var t="",t=this._match_pattern?this._input.read(this._starting_pattern):this._input.read(this._starting_pattern,this.__template_pattern),e=this._read_template();e;)this._match_pattern?e+=this._input.read(this._match_pattern):e+=this._input.readUntil(this.__template_pattern),t+=e,e=this._read_template();return this._until_after&&(t+=this._input.readUntilAfter(this._until_pattern)),t},_.prototype.__set_templated_pattern=function(){var t=[];this._disabled.php||t.push(this.__patterns.php._starting_pattern.source),this._disabled.handlebars||t.push(this.__patterns.handlebars._starting_pattern.source),this._disabled.erb||t.push(this.__patterns.erb._starting_pattern.source),this._disabled.django||(t.push(this.__patterns.django._starting_pattern.source),t.push(this.__patterns.django_value._starting_pattern.source),t.push(this.__patterns.django_comment._starting_pattern.source)),this._disabled.smarty||t.push(this.__patterns.smarty._starting_pattern.source),this._until_pattern&&t.push(this._until_pattern.source),this.__template_pattern=this._input.get_regexp("(?:"+t.join("|")+")")},_.prototype._read_template=function(){var t,e="",u=this._input.peek();return"<"===u?(t=this._input.peek(1),this._disabled.php||this._excluded.php||"?"!==t||(e=e||this.__patterns.php.read()),this._disabled.erb||this._excluded.erb||"%"!==t||(e=e||this.__patterns.erb.read())):"{"===u&&(this._disabled.handlebars||this._excluded.handlebars||(e=(e=(e=e||this.__patterns.handlebars_comment.read())||this.__patterns.handlebars_unescaped.read())||this.__patterns.handlebars.read()),this._disabled.django||(this._excluded.django||this._excluded.handlebars||(e=e||this.__patterns.django_value.read()),this._excluded.django||(e=(e=e||this.__patterns.django_comment.read())||this.__patterns.django.read())),this._disabled.smarty||this._disabled.django&&this._disabled.handlebars&&(e=(e=(e=e||this.__patterns.smarty_comment.read())||this.__patterns.smarty_literal.read())||this.__patterns.smarty.read())),e},t.exports.TemplatablePattern=_}],i.c=n,i.d=function(t,e,u){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:u})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var u=Object.create(null);if(i.r(u),Object.defineProperty(u,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(u,n,function(t){return e[t]}.bind(null,n));return u},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=0));"function"==typeof define&&define.amd?define([],function(){return{js_beautify:t}}):"undefined"!=typeof exports?exports.js_beautify=t:"undefined"!=typeof window?window.js_beautify=t:"undefined"!=typeof global&&(global.js_beautify=t)}(); -------------------------------------------------------------------------------- /view/adminhtml/web/template/ui/grid/cells/text.html: -------------------------------------------------------------------------------- 1 | 5 | 6 |
8 | --------------------------------------------------------------------------------