├── .codecov.yml ├── .easy.api.config ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ ├── feature_request.md │ └── question.md ├── issue_label_bot.yaml └── workflows │ ├── auto-label.yml │ ├── ci.yml │ ├── co.yml │ ├── pr-package.yml │ ├── pr-release.yml │ ├── release.yml │ └── stale.yml ├── .gitignore ├── .travis.yml ├── IDEA_CHANGELOG.md ├── LICENSE ├── README.md ├── README_CN.md ├── assets ├── close.png ├── no.png ├── ok.png ├── reset.svg └── yes.png ├── build.gradle.kts ├── common-api ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ ├── com │ │ └── itangcent │ │ │ ├── annotation │ │ │ └── script │ │ │ │ ├── ScriptIgnore.kt │ │ │ │ ├── ScriptReturn.kt │ │ │ │ ├── ScriptTypeName.kt │ │ │ │ └── ScriptUnIgnore.kt │ │ │ ├── common │ │ │ ├── constant │ │ │ │ ├── Attrs.kt │ │ │ │ ├── HttpMethod.kt │ │ │ │ └── Language.kt │ │ │ ├── http │ │ │ │ └── EntityUtils.kt │ │ │ ├── kit │ │ │ │ ├── KVUtils.kt │ │ │ │ ├── KitUtils.kt │ │ │ │ └── StreamKit.kt │ │ │ ├── model │ │ │ │ ├── Doc.kt │ │ │ │ ├── FormParam.kt │ │ │ │ ├── Header.kt │ │ │ │ ├── MethodDoc.kt │ │ │ │ ├── NamedValue.kt │ │ │ │ ├── Param.kt │ │ │ │ ├── PathParam.kt │ │ │ │ ├── Request.kt │ │ │ │ ├── Response.kt │ │ │ │ └── URL.kt │ │ │ └── utils │ │ │ │ └── FileSizeUtils.kt │ │ │ ├── http │ │ │ ├── ApacheHttpClient.kt │ │ │ ├── HttpClient.kt │ │ │ ├── HttpCookieStore.kt │ │ │ ├── HttpRequest.kt │ │ │ ├── RawContentType.kt │ │ │ └── RequestUtils.kt │ │ │ └── utils │ │ │ ├── ActionKeys.kt │ │ │ ├── AnyKit.kt │ │ │ ├── DefaultJsonSupport.kt │ │ │ ├── FuncKit.kt │ │ │ ├── JsonSupport.kt │ │ │ └── KClassKit.kt │ │ └── org │ │ └── apache │ │ └── http │ │ └── util │ │ └── EntityKits.kt │ └── test │ └── kotlin │ ├── com │ └── itangcent │ │ ├── common │ │ ├── constant │ │ │ └── HttpMethodTest.kt │ │ ├── http │ │ │ └── EntityUtilsTest.kt │ │ ├── kit │ │ │ ├── KVUtilsTest.kt │ │ │ ├── KitUtilsTest.kt │ │ │ └── RequestUtilsTest.kt │ │ ├── model │ │ │ ├── ModelsTest.kt │ │ │ └── URLTest.kt │ │ └── utils │ │ │ └── FileSizeUtilsTest.kt │ │ ├── http │ │ ├── ApacheHttpClientTest.kt │ │ ├── BasicHttpHeaderTest.kt │ │ └── BasicHttpParamTest.kt │ │ └── utils │ │ ├── AnyKitKtTest.kt │ │ └── FuncKitKtTest.kt │ └── org │ └── apache │ └── http │ └── util │ └── EntityKitsKtTest.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── idea-plugin ├── build.gradle.kts ├── gradle.properties ├── parts │ ├── pluginChanges.html │ └── pluginDescription.html └── src │ ├── main │ ├── kotlin │ │ └── com │ │ │ └── itangcent │ │ │ ├── ai │ │ │ ├── AIException.kt │ │ │ ├── AIMessages.kt │ │ │ ├── AIProvider.kt │ │ │ ├── AIService.kt │ │ │ ├── AIServiceCache.kt │ │ │ ├── AIServiceCacheSupport.kt │ │ │ ├── AIServiceChecker.kt │ │ │ ├── DeepSeekService.kt │ │ │ ├── LocalLLMClient.kt │ │ │ ├── LocalLLMServerDiscoverer.kt │ │ │ ├── LocalLLMService.kt │ │ │ └── OpenAIService.kt │ │ │ ├── cache │ │ │ ├── CacheManager.kt │ │ │ ├── DefaultHttpContextCacheHelper.kt │ │ │ └── HttpContextCacheHelper.kt │ │ │ ├── condition │ │ │ ├── AnnotatedCondition.kt │ │ │ ├── Condition.kt │ │ │ ├── ConditionEvaluator.kt │ │ │ ├── ConditionSupported.kt │ │ │ ├── Conditional.kt │ │ │ ├── DefaultConditionEvaluator.kt │ │ │ └── Exclusion.kt │ │ │ ├── debug │ │ │ └── LoggerCollector.kt │ │ │ ├── idea │ │ │ ├── binder │ │ │ │ └── DbBeanBinder.kt │ │ │ ├── condition │ │ │ │ ├── OnClassCondition.kt │ │ │ │ ├── OnMissingClassCondition.kt │ │ │ │ └── annotation │ │ │ │ │ ├── ConditionOnClass.kt │ │ │ │ │ └── ConditionOnMissingClass.kt │ │ │ ├── config │ │ │ │ └── CachedResourceResolver.kt │ │ │ ├── icons │ │ │ │ └── EasyIcons.kt │ │ │ ├── plugin │ │ │ │ ├── CustomInfoImpl.kt │ │ │ │ ├── Initializer.kt │ │ │ │ ├── actions │ │ │ │ │ ├── ApiCallAction.kt │ │ │ │ │ ├── ApiExportAction.kt │ │ │ │ │ ├── BasicAnAction.kt │ │ │ │ │ ├── FieldsToJson5Action.kt │ │ │ │ │ ├── FieldsToJsonAction.kt │ │ │ │ │ ├── FieldsToMessageAction.kt │ │ │ │ │ ├── FieldsToPropertiesAction.kt │ │ │ │ │ ├── MarkdownExportAction.kt │ │ │ │ │ ├── PostmanExportAction.kt │ │ │ │ │ ├── ScriptExecutorAction.kt │ │ │ │ │ └── SuvExportAction.kt │ │ │ │ ├── api │ │ │ │ │ ├── ClassApiExporterHelper.kt │ │ │ │ │ ├── cache │ │ │ │ │ │ ├── CachedRequestClassExporter.kt │ │ │ │ │ │ ├── DefaultFileApiCacheRepository.kt │ │ │ │ │ │ ├── FileApiCache.kt │ │ │ │ │ │ ├── FileApiCacheRepository.kt │ │ │ │ │ │ └── ProjectCacheRepository.kt │ │ │ │ │ ├── dashboard │ │ │ │ │ │ ├── ApiDashboardPanel.kt │ │ │ │ │ │ ├── ApiDashboardService.kt │ │ │ │ │ │ └── ApiDashboardToolWindow.kt │ │ │ │ │ ├── debug │ │ │ │ │ │ └── ScriptExecutor.kt │ │ │ │ │ ├── export │ │ │ │ │ │ ├── AdditionalField.kt │ │ │ │ │ │ ├── ExportChannel.kt │ │ │ │ │ │ ├── ExportDoc.kt │ │ │ │ │ │ ├── Orders.kt │ │ │ │ │ │ ├── UrlSelector.kt │ │ │ │ │ │ ├── condition │ │ │ │ │ │ │ ├── ConditionOnChannel.kt │ │ │ │ │ │ │ ├── ConditionOnDoc.kt │ │ │ │ │ │ │ ├── ConditionOnSimple.kt │ │ │ │ │ │ │ ├── OnChannelCondition.kt │ │ │ │ │ │ │ ├── OnDocCondition.kt │ │ │ │ │ │ │ └── OnSimpleCondition.kt │ │ │ │ │ │ ├── core │ │ │ │ │ │ │ ├── AdditionalParseHelper.kt │ │ │ │ │ │ │ ├── ApiHelper.kt │ │ │ │ │ │ │ ├── ClassExportRuleKeys.kt │ │ │ │ │ │ │ ├── ClassExporter.kt │ │ │ │ │ │ │ ├── CommentResolver.kt │ │ │ │ │ │ │ ├── DefaultAdditionalParseHelper.kt │ │ │ │ │ │ │ ├── DefaultClassExporter.kt │ │ │ │ │ │ │ ├── DefaultDocParseHelper.kt │ │ │ │ │ │ │ ├── DefaultFormatFolderHelper.kt │ │ │ │ │ │ │ ├── DefaultLinkResolver.kt │ │ │ │ │ │ │ ├── DefaultMethodDocBuilderListener.kt │ │ │ │ │ │ │ ├── DefaultRequestBuilderListener.kt │ │ │ │ │ │ │ ├── DocParseHelper.kt │ │ │ │ │ │ │ ├── EasyApiConfigProvider.kt │ │ │ │ │ │ │ ├── ExportContext.kt │ │ │ │ │ │ │ ├── Folder.kt │ │ │ │ │ │ │ ├── FormatFolderHelper.kt │ │ │ │ │ │ │ ├── LinkResolver.kt │ │ │ │ │ │ │ ├── MethodDocBuilderListener.kt │ │ │ │ │ │ │ ├── MethodFilter.kt │ │ │ │ │ │ │ ├── RequestBuilderListener.kt │ │ │ │ │ │ │ ├── RequestClassExporter.kt │ │ │ │ │ │ │ ├── ReservedResponseHandle.kt │ │ │ │ │ │ │ ├── ResolveMultiPath.kt │ │ │ │ │ │ │ └── StringResponseHandler.kt │ │ │ │ │ │ ├── curl │ │ │ │ │ │ │ ├── CurlExporter.kt │ │ │ │ │ │ │ └── CurlFormatter.kt │ │ │ │ │ │ ├── feign │ │ │ │ │ │ │ ├── FeignRequestClassExporter.kt │ │ │ │ │ │ │ ├── FeignTemplate.kt │ │ │ │ │ │ │ ├── RequestLineRequestMappingResolver.kt │ │ │ │ │ │ │ ├── SimpleFeignRequestClassExporter.kt │ │ │ │ │ │ │ └── SpringFeignClassName.kt │ │ │ │ │ │ ├── generic │ │ │ │ │ │ │ ├── GenericClassExportRuleKeys.kt │ │ │ │ │ │ │ ├── GenericMethodDocClassExporter.kt │ │ │ │ │ │ │ ├── GenericRequestClassExporter.kt │ │ │ │ │ │ │ ├── SimpleGenericMethodDocClassExporter.kt │ │ │ │ │ │ │ └── SimpleGenericRequestClassExporter.kt │ │ │ │ │ │ ├── http │ │ │ │ │ │ │ ├── HttpClientExporter.kt │ │ │ │ │ │ │ ├── HttpClientFileSaver.kt │ │ │ │ │ │ │ └── HttpClientFormatter.kt │ │ │ │ │ │ ├── jaxrs │ │ │ │ │ │ │ ├── JAXRSBaseAnnotationParser.kt │ │ │ │ │ │ │ ├── JAXRSClassName.kt │ │ │ │ │ │ │ ├── JAXRSCustomHttpMethodResolver.kt │ │ │ │ │ │ │ ├── JAXRSRequestClassExporter.kt │ │ │ │ │ │ │ └── SimpleJAXRSRequestClassExporter.kt │ │ │ │ │ │ ├── markdown │ │ │ │ │ │ │ ├── DefaultMarkdownFormatter.kt │ │ │ │ │ │ │ ├── MarkdownApiExporter.kt │ │ │ │ │ │ │ ├── MarkdownEscapeUtils.kt │ │ │ │ │ │ │ ├── MarkdownExportRuleKeys.kt │ │ │ │ │ │ │ ├── MarkdownFormatter.kt │ │ │ │ │ │ │ ├── MarkdownFormatterProvider.kt │ │ │ │ │ │ │ ├── MixMarkdownFormatter.kt │ │ │ │ │ │ │ ├── TemplateExpressions.kt │ │ │ │ │ │ │ ├── TemplateMarkdownFormatter.kt │ │ │ │ │ │ │ └── Writer.kt │ │ │ │ │ │ ├── postman │ │ │ │ │ │ │ ├── DefaultPostmanApiHelper.kt │ │ │ │ │ │ │ ├── Emojis.kt │ │ │ │ │ │ │ ├── PostmanApiExporter.kt │ │ │ │ │ │ │ ├── PostmanApiHelper.kt │ │ │ │ │ │ │ ├── PostmanCachedApiHelper.kt │ │ │ │ │ │ │ ├── PostmanConfigProvider.kt │ │ │ │ │ │ │ ├── PostmanExportRuleKeys.kt │ │ │ │ │ │ │ ├── PostmanFormatFolderHelper.kt │ │ │ │ │ │ │ ├── PostmanFormatter.kt │ │ │ │ │ │ │ ├── PostmanKits.kt │ │ │ │ │ │ │ ├── PostmanRequestBuilderListener.kt │ │ │ │ │ │ │ └── PostmanUrls.kt │ │ │ │ │ │ ├── rule │ │ │ │ │ │ │ └── RequestRuleWrap.kt │ │ │ │ │ │ ├── spring │ │ │ │ │ │ │ ├── ActuatorEndpointExporter.kt │ │ │ │ │ │ │ ├── CustomSpringControllerAnnotationResolver.kt │ │ │ │ │ │ │ ├── CustomSpringRequestMappingResolver.kt │ │ │ │ │ │ │ ├── DefaultSpringRequestMappingResolver.kt │ │ │ │ │ │ │ ├── SimpleSpringRequestClassExporter.kt │ │ │ │ │ │ │ ├── SpringClassName.kt │ │ │ │ │ │ │ ├── SpringControllerAnnotationResolver.kt │ │ │ │ │ │ │ ├── SpringRequestClassExporter.kt │ │ │ │ │ │ │ ├── SpringRequestMappingResolver.kt │ │ │ │ │ │ │ ├── StandardSpringControllerAnnotationResolver.kt │ │ │ │ │ │ │ └── StarandSpringRequestMappingResolver.kt │ │ │ │ │ │ ├── suv │ │ │ │ │ │ │ └── SuvApiExporter.kt │ │ │ │ │ │ └── translation │ │ │ │ │ │ │ ├── APITranslationHelper.kt │ │ │ │ │ │ │ └── TranslationRequestBuilderListener.kt │ │ │ │ │ └── infer │ │ │ │ │ │ ├── AIMethodInferHelper.kt │ │ │ │ │ │ ├── AIPromptFormatter.kt │ │ │ │ │ │ ├── DefaultMethodInferHelper.kt │ │ │ │ │ │ ├── MethodInferHelper.kt │ │ │ │ │ │ ├── MethodInferHelperFactory.kt │ │ │ │ │ │ ├── MethodInferHelperProvider.kt │ │ │ │ │ │ └── PsiInferenceCollector.kt │ │ │ │ ├── condition │ │ │ │ │ ├── ConditionOnSetting.kt │ │ │ │ │ └── OnSettingCondition.kt │ │ │ │ ├── config │ │ │ │ │ └── EnhancedConfigReader.kt │ │ │ │ ├── configurable │ │ │ │ │ ├── AbstractEasyApiConfigurable.kt │ │ │ │ │ ├── AbstractEasyApiSettingGUI.kt │ │ │ │ │ ├── EasyApiConfigurable.kt │ │ │ │ │ ├── EasyApiOtherConfigurable.kt │ │ │ │ │ ├── EasyApiRecommendConfigurable.kt │ │ │ │ │ ├── EasyApiRemoteConfigurable.kt │ │ │ │ │ ├── EasyApiSettingAIConfigurable.kt │ │ │ │ │ ├── EasyApiSettingBuiltInConfigConfigurable.kt │ │ │ │ │ └── EasyApiSettingGUI.kt │ │ │ │ ├── dialog │ │ │ │ │ ├── AskWithApplyAllDialog.kt │ │ │ │ │ ├── ChooseWithTipDialog.kt │ │ │ │ │ ├── ContextDialog.kt │ │ │ │ │ ├── EasyApiSettingAIGUI.form │ │ │ │ │ ├── EasyApiSettingAIGUI.kt │ │ │ │ │ ├── EasyApiSettingBuiltInConfigGUI.form │ │ │ │ │ ├── EasyApiSettingBuiltInConfigGUI.kt │ │ │ │ │ ├── EasyApiSettingGUI.form │ │ │ │ │ ├── EasyApiSettingGUI.kt │ │ │ │ │ ├── EasyApiSettingOtherGUI.form │ │ │ │ │ ├── EasyApiSettingOtherGUI.kt │ │ │ │ │ ├── EasyApiSettingRecommendGUI.form │ │ │ │ │ ├── EasyApiSettingRecommendGUI.kt │ │ │ │ │ ├── EasyApiSettingRemoteConfigGUI.form │ │ │ │ │ ├── EasyApiSettingRemoteConfigGUI.kt │ │ │ │ │ ├── ScriptExecutorDialog.form │ │ │ │ │ ├── ScriptExecutorDialog.kt │ │ │ │ │ ├── SearchSupport.kt │ │ │ │ │ ├── SuvApiExportDialog.kt │ │ │ │ │ └── TriggerSupport.kt │ │ │ │ ├── format │ │ │ │ │ ├── Json5Formatter.kt │ │ │ │ │ ├── MessageFormatter.kt │ │ │ │ │ ├── PropertiesFormatter.kt │ │ │ │ │ └── SimpleJsonFormatter.kt │ │ │ │ ├── rule │ │ │ │ │ ├── FieldPathMatcher.kt │ │ │ │ │ ├── FieldPatternRuleParser.kt │ │ │ │ │ ├── GroovyRuleParser.kt │ │ │ │ │ ├── JsRuleParser.kt │ │ │ │ │ ├── RuleComputorKit.kt │ │ │ │ │ ├── RuleToolUtils.kt │ │ │ │ │ ├── ScriptRuleParser.kt │ │ │ │ │ ├── StandardJdkRuleParser.kt │ │ │ │ │ ├── SuvRuleContext.kt │ │ │ │ │ ├── SuvRuleParser.kt │ │ │ │ │ └── UnsupportedScriptException.kt │ │ │ │ ├── settings │ │ │ │ │ ├── DefaultSettingBinder.kt │ │ │ │ │ ├── EnumProcessInitializer.kt │ │ │ │ │ ├── EventRecords.kt │ │ │ │ │ ├── HttpClientType.kt │ │ │ │ │ ├── MarkdownFormatType.kt │ │ │ │ │ ├── PostmanExportMode.kt │ │ │ │ │ ├── PostmanJson5FormatType.kt │ │ │ │ │ ├── SettingBinder.kt │ │ │ │ │ ├── Settings.kt │ │ │ │ │ ├── XmlSettingBinder.kt │ │ │ │ │ ├── helper │ │ │ │ │ │ ├── AISettingsHelper.kt │ │ │ │ │ │ ├── BuiltInConfigSettingsHelper.kt │ │ │ │ │ │ ├── CommonSettingsHelper.kt │ │ │ │ │ │ ├── DefaultPostmanSettingsHelper.kt │ │ │ │ │ │ ├── HttpSettingsHelperImpl.kt │ │ │ │ │ │ ├── IntelligentSettingsHelper.kt │ │ │ │ │ │ ├── MarkdownSettingsHelper.kt │ │ │ │ │ │ ├── MemoryPostmanSettingsHelper.kt │ │ │ │ │ │ ├── PostmanSettingsHelper.kt │ │ │ │ │ │ ├── RecommendConfigSettingsHelper.kt │ │ │ │ │ │ ├── RemoteConfigSettingsHelper.kt │ │ │ │ │ │ └── SupportSettingsHelper.kt │ │ │ │ │ └── xml │ │ │ │ │ │ ├── ApplicationSettings.kt │ │ │ │ │ │ ├── ApplicationSettingsComponent.kt │ │ │ │ │ │ ├── ProjectSettings.kt │ │ │ │ │ │ └── ProjectSettingsComponent.kt │ │ │ │ ├── support │ │ │ │ │ └── IdeaSupport.kt │ │ │ │ ├── ui │ │ │ │ │ └── UI.kt │ │ │ │ └── utils │ │ │ │ │ ├── AIUtils.kt │ │ │ │ │ ├── AbstractStorage.kt │ │ │ │ │ ├── LocalStorage.kt │ │ │ │ │ ├── NotificationUtils.kt │ │ │ │ │ ├── RegexUtils.kt │ │ │ │ │ ├── SessionStorage.kt │ │ │ │ │ └── Storage.kt │ │ │ ├── psi │ │ │ │ ├── DisableDocSupport.kt │ │ │ │ ├── PsiClassFinder.kt │ │ │ │ ├── PsiClassResource.kt │ │ │ │ ├── PsiMethodResource.kt │ │ │ │ ├── PsiMethodSet.kt │ │ │ │ ├── PsiMethodUtil.kt │ │ │ │ ├── PsiResource.kt │ │ │ │ └── UltimateDocHelper.kt │ │ │ ├── sqlite │ │ │ │ └── SqliteDataResourceHelper.kt │ │ │ ├── swing │ │ │ │ ├── ActiveWindowProvider.kt │ │ │ │ ├── DefaultMessagesHelper.kt │ │ │ │ ├── EasyApiTreeCellRenderer.kt │ │ │ │ ├── IconCustomized.kt │ │ │ │ ├── ListenerKit.kt │ │ │ │ ├── MessagesHelper.kt │ │ │ │ ├── SafeHashHelper.kt │ │ │ │ ├── SimpleActiveWindowProvider.kt │ │ │ │ └── ToolTipAble.kt │ │ │ └── utils │ │ │ │ ├── Charsets.kt │ │ │ │ ├── ContextualPsiClassHelper.kt │ │ │ │ ├── CustomizedPsiClassHelper.kt │ │ │ │ ├── DefaultFileSaveHelper.kt │ │ │ │ ├── DefaultFileSelectHelper.kt │ │ │ │ ├── DefaultModuleHelper.kt │ │ │ │ ├── DigestUtils.kt │ │ │ │ ├── FileSaveHelper.kt │ │ │ │ ├── FileSelectHelper.kt │ │ │ │ ├── FormatterHelper.kt │ │ │ │ ├── GsonExUtils.kt │ │ │ │ ├── JacksonUtils.kt │ │ │ │ ├── MavenHelper.kt │ │ │ │ ├── ModuleHelper.kt │ │ │ │ ├── ProjectHelper.kt │ │ │ │ ├── RuleComputeListenerRegistry.kt │ │ │ │ ├── SwingUtils.kt │ │ │ │ └── SystemProvider.kt │ │ │ ├── intellij │ │ │ ├── context │ │ │ │ ├── AutoClear.kt │ │ │ │ └── AutoClearSupporter.kt │ │ │ ├── extend │ │ │ │ ├── ActionContextKit.kt │ │ │ │ ├── AnyKit.kt │ │ │ │ ├── GsonKit.kt │ │ │ │ ├── ThrottleKit.kt │ │ │ │ └── guice │ │ │ │ │ └── Injectors.kt │ │ │ └── util │ │ │ │ ├── CacheAble.kt │ │ │ │ ├── DefaultCacheAle.kt │ │ │ │ ├── FileType.kt │ │ │ │ └── KVKit.kt │ │ │ ├── logger │ │ │ ├── ConfigurableLogger.kt │ │ │ └── LoggerProvider.kt │ │ │ ├── order │ │ │ ├── Order.kt │ │ │ └── Ordered.kt │ │ │ ├── spi │ │ │ ├── AbstractSpiBeanProvider.kt │ │ │ ├── SpiCompositeBeanProvider.kt │ │ │ ├── SpiCompositeLoader.kt │ │ │ └── SpiSingleBeanProvider.kt │ │ │ ├── suv │ │ │ └── http │ │ │ │ ├── AbstractHttpClientProvider.kt │ │ │ │ ├── ApacheHttpClientProvider.kt │ │ │ │ ├── CookiePersistenceHelper.kt │ │ │ │ ├── HttpClientProvider.kt │ │ │ │ ├── HttpClientScriptInterceptor.kt │ │ │ │ ├── OkHttpClient.kt │ │ │ │ └── OkHttpClientProvider.kt │ │ │ └── utils │ │ │ ├── Action.kt │ │ │ ├── ArrayKit.kt │ │ │ ├── Emojis.kt │ │ │ ├── EnumKit.kt │ │ │ ├── ExtensibleKit.kt │ │ │ ├── FileKit.kt │ │ │ ├── GiteeSupport.kt │ │ │ ├── Initializable.kt │ │ │ ├── NonReentrant.kt │ │ │ ├── ReflectionKit.kt │ │ │ ├── StringKit.kt │ │ │ └── TemplateKit.kt │ └── resources │ │ ├── .default.built.in.easy.api.config │ │ ├── .default.remote.easy.api.config │ │ ├── .recommend.easy.api.config │ │ ├── META-INF │ │ ├── easy-api-java.xml │ │ ├── easy-api-kotlin.xml │ │ ├── easy-api-scala.xml │ │ ├── plugin.xml │ │ └── services │ │ │ ├── com.itangcent.ai.AIService │ │ │ ├── com.itangcent.common.logger.ILogger │ │ │ ├── com.itangcent.common.spi.SetupAble │ │ │ ├── com.itangcent.condition.Condition │ │ │ ├── com.itangcent.idea.plugin.Initializer │ │ │ ├── com.itangcent.idea.plugin.api.export.core.ClassExporter │ │ │ ├── com.itangcent.idea.plugin.api.export.core.MethodDocBuilderListener │ │ │ ├── com.itangcent.idea.plugin.api.export.core.RequestBuilderListener │ │ │ ├── com.itangcent.idea.plugin.api.export.spring.SpringControllerAnnotationResolver │ │ │ ├── com.itangcent.idea.plugin.api.export.spring.SpringRequestMappingResolver │ │ │ ├── com.itangcent.intellij.CustomInfo │ │ │ ├── com.itangcent.intellij.config.ConfigProvider │ │ │ └── com.itangcent.suv.http.HttpClientProvider │ │ └── assets │ │ ├── class.svg │ │ ├── close.svg │ │ ├── collapseall.svg │ │ ├── export.svg │ │ ├── import.svg │ │ ├── link.svg │ │ ├── method.svg │ │ ├── module.svg │ │ ├── moduleGroup.svg │ │ ├── ok.svg │ │ ├── refresh.svg │ │ ├── remove.svg │ │ ├── run.svg │ │ ├── upFolder.svg │ │ └── webFolder.svg │ └── test │ ├── kotlin │ └── com │ │ └── itangcent │ │ ├── cache │ │ ├── CacheSwitcherTest.kt │ │ └── DefaultHttpContextCacheHelperTest.kt │ │ ├── condition │ │ ├── AnnotatedConditionTest.kt │ │ └── DefaultConditionEvaluatorTest.kt │ │ ├── debug │ │ └── LoggerCollectorTest.kt │ │ ├── idea │ │ ├── binder │ │ │ └── DbBeanBinderTest.kt │ │ ├── condition │ │ │ ├── OnClassConditionTest.kt │ │ │ └── OnMissingClassConditionTest.kt │ │ ├── config │ │ │ └── CachedResourceResolverTest.kt │ │ ├── icons │ │ │ └── EasyIconsTest.kt │ │ ├── plugin │ │ │ ├── CustomInfoImplTest.kt │ │ │ ├── api │ │ │ │ ├── ClassApiExporterHelperTest.kt │ │ │ │ ├── cache │ │ │ │ │ ├── CachedRequestClassExporterTest.kt │ │ │ │ │ ├── FileApiCacheRepositoryTest.kt │ │ │ │ │ └── ProjectCacheRepositoryTest.kt │ │ │ │ ├── export │ │ │ │ │ ├── UrlSelectorTest.kt │ │ │ │ │ ├── condition │ │ │ │ │ │ ├── OnChannelConditionTest.kt │ │ │ │ │ │ ├── OnDocConditionTest.kt │ │ │ │ │ │ └── OnSimpleConditionTest.kt │ │ │ │ │ ├── core │ │ │ │ │ │ ├── AdditionalParseHelperTest.kt │ │ │ │ │ │ ├── ApiHelperTest.kt │ │ │ │ │ │ ├── CommentResolverTest.kt │ │ │ │ │ │ ├── DefaultAdditionalParseHelperTest.kt │ │ │ │ │ │ ├── DefaultDocParseHelperTest.kt │ │ │ │ │ │ ├── DefaultFormatFolderHelperTest.kt │ │ │ │ │ │ ├── DefaultLinkResolverTest.kt │ │ │ │ │ │ ├── DefaultMethodDocBuilderListenerTest.kt │ │ │ │ │ │ ├── DefaultMethodInferHelperTest.kt │ │ │ │ │ │ ├── DefaultRequestBuilderListenerTest.kt │ │ │ │ │ │ ├── EasyApiConfigProviderTest.kt │ │ │ │ │ │ └── ReservedResponseHandleTest.kt │ │ │ │ │ ├── curl │ │ │ │ │ │ ├── CurlExporterTest.kt │ │ │ │ │ │ └── CurlFormatterTest.kt │ │ │ │ │ ├── feign │ │ │ │ │ │ ├── FeignRequestClassExporterTest.kt │ │ │ │ │ │ ├── RequestLineRequestMappingResolverTest.kt │ │ │ │ │ │ └── SimpleFeignRequestClassExporterTest.kt │ │ │ │ │ ├── generic │ │ │ │ │ │ ├── GenericMethodDocClassExporterTest.kt │ │ │ │ │ │ ├── GenericRequestClassExporterTest.kt │ │ │ │ │ │ ├── SimpleGenericMethodDocClassExporterTest.kt │ │ │ │ │ │ └── SimpleGenericRequestClassExporterTest.kt │ │ │ │ │ ├── http │ │ │ │ │ │ ├── HttpClientExporterTest.kt │ │ │ │ │ │ └── HttpClientFormatterTest.kt │ │ │ │ │ ├── jaxrs │ │ │ │ │ │ ├── JAXRSRequestClassExporterTest.kt │ │ │ │ │ │ └── SimpleJAXRSRequestClassExporterTest.kt │ │ │ │ │ ├── markdown │ │ │ │ │ │ ├── MarkdownApiExporterTest.kt │ │ │ │ │ │ ├── MarkdownEscapeUtilsTest.kt │ │ │ │ │ │ ├── MarkdownFormatterProviderTest.kt │ │ │ │ │ │ ├── MixMarkdownFormatterTest.kt │ │ │ │ │ │ ├── TemplateExpressionsTest.kt │ │ │ │ │ │ └── TemplateMarkdownFormatterTest.kt │ │ │ │ │ ├── postman │ │ │ │ │ │ ├── DefaultPostmanApiHelperTest.kt │ │ │ │ │ │ ├── PostmanApiExporterTest.kt │ │ │ │ │ │ ├── PostmanCachedApiHelperTest.kt │ │ │ │ │ │ ├── PostmanConfigProviderTest.kt │ │ │ │ │ │ ├── PostmanFormatFolderHelperTest.kt │ │ │ │ │ │ ├── PostmanFormatterTest.kt │ │ │ │ │ │ ├── PostmanSpringClassExporterBaseTest.kt │ │ │ │ │ │ ├── PostmanSpringRequestClassExporterTest.kt │ │ │ │ │ │ └── PostmanWorkspaceTest.kt │ │ │ │ │ ├── rule │ │ │ │ │ │ └── RequestRuleWrapTest.kt │ │ │ │ │ └── spring │ │ │ │ │ │ ├── ActuatorEndpointExporterTest.kt │ │ │ │ │ │ ├── CustomSpringRequestMappingResolverTest.kt │ │ │ │ │ │ ├── DefaultSpringRequestMappingResolverTest.kt │ │ │ │ │ │ ├── SimpleSpringRequestClassExporterTest.kt │ │ │ │ │ │ ├── SpringRequestClassExporterTest.kt │ │ │ │ │ │ └── StandardSpringRequestMappingResolverTest.kt │ │ │ │ └── infer │ │ │ │ │ ├── AIPromptFormatterTest.kt │ │ │ │ │ ├── MethodInferHelperFactoryTest.kt │ │ │ │ │ └── PsiInferenceCollectorTest.kt │ │ │ ├── condition │ │ │ │ └── OnSettingConditionTest.kt │ │ │ ├── config │ │ │ │ └── EnhancedConfigReaderTest.kt │ │ │ ├── configurable │ │ │ │ └── AbstractEasyApiConfigurableTest.kt │ │ │ ├── format │ │ │ │ ├── Json5FormatterTest.kt │ │ │ │ ├── MessageFormatterTest.kt │ │ │ │ ├── PropertiesFormatterTest.kt │ │ │ │ └── SimpleJsonFormatterTest.kt │ │ │ ├── rule │ │ │ │ ├── FieldPatternRuleParserTest.kt │ │ │ │ ├── GroovyRuleParserTest.kt │ │ │ │ ├── JsRuleParserTest.kt │ │ │ │ ├── RuleParserBaseTest.kt │ │ │ │ ├── RuleToolUtilsTest.kt │ │ │ │ ├── ScriptClassContextBaseTest.kt │ │ │ │ ├── ScriptDuckTypeContextTest.kt │ │ │ │ ├── ScriptExplicitClassContextTest.kt │ │ │ │ ├── ScriptPsiClassContextTest.kt │ │ │ │ ├── ScriptPsiTypeContextTest.kt │ │ │ │ ├── StandardJdkRuleParserTest.kt │ │ │ │ └── SuvRuleParserTest.kt │ │ │ ├── settings │ │ │ │ ├── DefaultSettingBinderTest.kt │ │ │ │ ├── ETHUtils.kt │ │ │ │ ├── EnumProcessInitializerTest.kt │ │ │ │ ├── EventRecordsTest.kt │ │ │ │ ├── SettingsTest.kt │ │ │ │ ├── XmlSettingBinderTest.kt │ │ │ │ └── helper │ │ │ │ │ ├── AISettingsHelperTest.kt │ │ │ │ │ ├── BuiltInConfigSettingsHelperTest.kt │ │ │ │ │ ├── CommonSettingsHelperTest.kt │ │ │ │ │ ├── DefaultPostmanSettingsHelperTest.kt │ │ │ │ │ ├── HttpSettingsHelperTest.kt │ │ │ │ │ ├── IntelligentSettingsHelperTest.kt │ │ │ │ │ ├── MarkdownSettingsHelperTest.kt │ │ │ │ │ ├── MemoryPostmanSettingsHelperTest.kt │ │ │ │ │ ├── RecommendConfigLoaderTest.kt │ │ │ │ │ ├── RecommendConfigSettingsHelperTest.kt │ │ │ │ │ ├── RemoteConfigSettingsHelperTest.kt │ │ │ │ │ ├── SettingsHelperTest.kt │ │ │ │ │ └── SupportSettingsHelperTest.kt │ │ │ └── utils │ │ │ │ ├── AIUtilsTest.kt │ │ │ │ ├── AbstractStorageTest.kt │ │ │ │ ├── LocalStorageTest.kt │ │ │ │ ├── RegexUtilsTest.kt │ │ │ │ └── SessionStorageTest.kt │ │ ├── psi │ │ │ ├── DisableDocSupportTest.kt │ │ │ ├── PsiMethodSetTest.kt │ │ │ ├── PsiMethodUtilTest.kt │ │ │ ├── PsiResourceTest.kt │ │ │ └── UltimateDocHelperTest.kt │ │ ├── sqlite │ │ │ └── SqliteDataResourceHelperTest.kt │ │ ├── swing │ │ │ ├── DefaultMessagesHelperTest.kt │ │ │ ├── EasyApiTreeCellRendererTest.kt │ │ │ ├── MessagesHelperTest.kt │ │ │ └── SafeHashHelperTest.kt │ │ └── utils │ │ │ ├── AnyKitTest.kt │ │ │ ├── ConfigurableLoggerTest.kt │ │ │ ├── ContextualPsiClassHelperBaseTest.kt │ │ │ ├── ContextualPsiClassHelperTest.kt │ │ │ ├── CustomizedPsiClassHelperTest.kt │ │ │ ├── DefaultModuleHelperTest.kt │ │ │ ├── DefaultSystemProviderTest.kt │ │ │ ├── DigestUtilsTest.kt │ │ │ ├── FormatterHelperTest.kt │ │ │ ├── GsonExUtilsTest.kt │ │ │ ├── GsonKitTest.kt │ │ │ ├── IOUtilsTest.kt │ │ │ ├── JacksonUtilsTest.kt │ │ │ ├── KVKitTest.kt │ │ │ ├── MavenHelperTest.kt │ │ │ ├── ProjectHelperTest.kt │ │ │ └── SwingUtilsTest.kt │ │ ├── intellij │ │ ├── config │ │ │ └── ConfigProviderTest.kt │ │ ├── extend │ │ │ ├── ActionContextKitTest.kt │ │ │ └── ThrottleKitTest.kt │ │ └── util │ │ │ ├── CacheAbleTest.kt │ │ │ └── FileTypeTest.kt │ │ ├── logger │ │ └── LoggerProviderTest.kt │ │ ├── mock │ │ ├── ConstantModuleHelper.kt │ │ ├── CrossPlatformKit.kt │ │ ├── EmptyMessagesHelper.kt │ │ ├── FakeExportContext.kt │ │ ├── FileSaveHelperAdaptor.kt │ │ ├── ImmutableSystemProvider.kt │ │ ├── MockKit.kt │ │ └── SettingBinderAdaptor.kt │ │ ├── order │ │ └── OrderedTest.kt │ │ ├── spi │ │ ├── SpiCompositeBeanProviderTest.kt │ │ └── SpiCompositeLoaderTest.kt │ │ ├── suv │ │ └── http │ │ │ ├── AbstractHttpClientProviderTest.kt │ │ │ ├── CookiePersistenceHelperTest.kt │ │ │ ├── DefaultHttpClientProviderTest.kt │ │ │ ├── HttpClientProviderTest.kt │ │ │ ├── HttpClientScriptInterceptorTest.kt │ │ │ └── OkHttpClientTest.kt │ │ ├── test │ │ ├── ActionContextKit.kt │ │ ├── AssertKits.kt │ │ ├── HttpClientProviderMockBuilder.kt │ │ ├── IconLoaderHeadlessSupport.kt │ │ ├── ResultLoader.kt │ │ ├── ResultLoaderTest.kt │ │ ├── SelectWorkDirOrFileKt.kt │ │ ├── StringResource.kt │ │ └── TimeZoneKit.kt │ │ ├── testFramework │ │ ├── FileKit.kt │ │ └── PluginContextLightCodeInsightFixtureTestCase.kt │ │ └── utils │ │ ├── ExtensibleKitTest.kt │ │ ├── FileKitKtTest.kt │ │ ├── GiteeSupportTest.kt │ │ ├── NonReentrantTest.kt │ │ ├── ReflectionKitTest.kt │ │ ├── StringKitKtTest.kt │ │ ├── TemplateKitTest.kt │ │ └── WaitHelper.kt │ └── resources │ ├── META-INF │ └── services │ │ ├── com.itangcent.idea.icons.IconLoader │ │ └── com.itangcent.spi.MyService │ ├── annotation │ ├── JsonIgnore.java │ ├── JsonProperty.java │ ├── MyController.java │ └── Public.java │ ├── api │ ├── BaseController.java │ ├── CustomCtrl.java │ ├── DefaultCtrl.java │ ├── IUserApi.java │ ├── InferDemoCtrl.java │ ├── MyCtrl.java │ ├── NameCtrl.java │ ├── TestCtrl.java │ ├── UserApiImpl.java │ ├── UserCtrl.java │ ├── ValidationCtrl.java │ ├── actuator │ │ ├── ControllerAnnEndpoint.java │ │ ├── RestControllerAnnEndpoint.java │ │ ├── StandardEndpoint.java │ │ └── WebAnnEndpoint.java │ ├── feign │ │ ├── PrimitiveUserClient.java │ │ └── UserClient.java │ └── jaxrs │ │ ├── MyGet.java │ │ ├── MyPut.java │ │ ├── UserDTO.java │ │ └── UserResource.java │ ├── cases │ ├── LinkCase.java │ ├── NestedClass.java │ └── NestedClassB.java │ ├── client │ └── UserClient.java │ ├── config │ ├── .easy.api.config │ ├── .easy.api.yaml │ ├── .easy.api.yml │ ├── .postman.config │ ├── .postman.yaml │ ├── .postman.yml │ └── a │ │ ├── .easy.api.config │ │ ├── .easy.api.yaml │ │ ├── .easy.api.yml │ │ ├── .postman.config │ │ ├── .postman.yaml │ │ └── .postman.yml │ ├── constant │ ├── Add.java │ ├── JavaVersion.java │ ├── Numbers.java │ ├── Update.java │ ├── UserType.java │ └── UserTypeConstant.java │ ├── demo.properties │ ├── feign │ ├── Body.java │ ├── Headers.java │ ├── Param.java │ └── RequestLine.java │ ├── jaxrs │ ├── BeanParam.java │ ├── CookieParam.java │ ├── DELETE.java │ ├── DefaultValue.java │ ├── FormParam.java │ ├── GET.java │ ├── HEAD.java │ ├── HeaderParam.java │ ├── HttpMethod.java │ ├── OPTIONS.java │ ├── PATCH.java │ ├── POST.java │ ├── PUT.java │ ├── Path.java │ ├── PathParam.java │ └── QueryParam.java │ ├── jdk │ ├── AbstractMap.fava │ ├── Boolean.fava │ ├── Collection.fava │ ├── Comparable.fava │ ├── Deprecated.fava │ ├── HashMap.fava │ ├── Integer.fava │ ├── Iterable.fava │ ├── LinkedList.fava │ ├── List.fava │ ├── LocalDate.fava │ ├── LocalDateTime.fava │ ├── Long.fava │ ├── Map.fava │ ├── Number.fava │ ├── Object.fava │ ├── String.fava │ └── Void.fava │ ├── model │ ├── CommentDemo.java │ ├── CustomMap.java │ ├── Default.java │ ├── IResult.java │ ├── Model.java │ ├── Node.java │ ├── PageRequest.java │ ├── Result.java │ ├── Root.java │ ├── SubModel.java │ ├── UserInfo.java │ └── ValidationGroupedDemoDto.java │ ├── result │ ├── com.itangcent.idea.plugin.api.call.ApiCallerTest.ExportFailedApiCallerTest.txt │ ├── com.itangcent.idea.plugin.api.call.ApiCallerTest.WaitExportFailedApiCallerTest.txt │ ├── com.itangcent.idea.plugin.api.export.curl.CurlExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.curl.CurlFormatterTest.txt │ ├── com.itangcent.idea.plugin.api.export.feign.FeignRequestClassExporterTest.testExportFromPrimitiveUserClientPsiClass.txt │ ├── com.itangcent.idea.plugin.api.export.feign.FeignRequestClassExporterTest.testExportFromUserClient.txt │ ├── com.itangcent.idea.plugin.api.export.generic.GenericMethodDocClassExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.http.HttpClientExporterTest.existedFile.txt │ ├── com.itangcent.idea.plugin.api.export.http.HttpClientExporterTest.newFile.txt │ ├── com.itangcent.idea.plugin.api.export.http.HttpClientFormatterTest.testParseRequests.txt │ ├── com.itangcent.idea.plugin.api.export.http.HttpClientFormatterTest.testParseRequestsToExistedDoc.txt │ ├── com.itangcent.idea.plugin.api.export.jaxrs.JAXRSRequestClassExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.markdown.MarkdownApiExporterTest.CustomizedDirectorySpringMarkdownApiExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.markdown.MarkdownApiExporterTest.DirectorySpringMarkdownApiExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.markdown.MarkdownApiExporterTest.GenericMethodMarkdownApiExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.markdown.MarkdownApiExporterTest.SpringMarkdownApiExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.markdown.MarkdownApiExporterTest.SpringUltimateMarkdownApiExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanApiExporterTest.DirectorySpringPostmanApiExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanApiExporterTest.GenericMethodPostmanApiExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanApiExporterTest.ModeCopyPostmanApiExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanApiExporterTest.ModeUpdatePostmanApiExporterTest.collection-123456789.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanApiExporterTest.ModeUpdatePostmanApiExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanApiExporterTest.SpringPostmanApiExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanFormatterTest.testParseRequests.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanFormatterTest.testParseRequestsToCollection-original-collection.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanFormatterTest.testParseRequestsToCollection.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanFormatterTest.testParseRequestsWithWrapCollection.txt │ ├── com.itangcent.idea.plugin.api.export.postman.PostmanSpringRequestClassExporterTest.txt │ ├── com.itangcent.idea.plugin.api.export.spring.SpringRequestClassExporterTest.testExportFromTestCtrlWithExpanded.txt │ ├── com.itangcent.idea.plugin.api.export.spring.SpringRequestClassExporterTest.testExportFromTestCtrlWithOutExpanded.txt │ ├── com.itangcent.idea.plugin.api.export.spring.SpringRequestClassExporterTest.testExportFromUserApi.txt │ ├── com.itangcent.idea.plugin.api.export.spring.SpringRequestClassExporterTest.testExportFromUserCtrl.txt │ ├── com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.EmptyRecommendEnhancedConfigReaderTest.log.txt │ ├── com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.foreach.field.txt │ ├── com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.foreach.txt │ ├── com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.foreach.field.txt │ ├── com.itangcent.idea.plugin.rule.StandardJdkRuleParserTest.runtime.log.txt │ ├── com.itangcent.idea.plugin.settings.helper.RecommendConfigLoaderTest.txt │ ├── com.itangcent.idea.plugin.settings.helper.RecommendConfigSettingsHelperTest.txt │ ├── com.itangcent.idea.utils.ContextualPsiClassHelperTest.CachedContextualPsiClassHelperTest.1.txt │ ├── com.itangcent.idea.utils.ContextualPsiClassHelperTest.CachedContextualPsiClassHelperTest.2.txt │ ├── com.itangcent.idea.utils.ContextualPsiClassHelperTest.NoCachedContextualPsiClassHelperTest.1.txt │ ├── com.itangcent.idea.utils.ContextualPsiClassHelperTest.NoCachedContextualPsiClassHelperTest.2.txt │ ├── com.itangcent.test.ResultLoaderTest.sub.txt │ └── com.itangcent.test.ResultLoaderTest.txt │ ├── spring │ ├── AliasFor.java │ ├── ControllerEndpoint.java │ ├── DeleteOperation.java │ ├── Endpoint.java │ ├── FakeMapping.java │ ├── FeignClient.java │ ├── GetMapping.java │ ├── ModelAttribute.java │ ├── MyPostMapping.java │ ├── PostMapping.java │ ├── PutMapping.java │ ├── ReadOperation.java │ ├── RequestBody.java │ ├── RequestHeader.java │ ├── RequestMapping.java │ ├── RequestMethod.java │ ├── RequestParam.java │ ├── RestController.java │ ├── RestControllerEndpoint.java │ ├── Selector.java │ ├── WebEndpoint.java │ └── WriteOperation.java │ └── validation │ ├── Default.java │ ├── NotBlank.java │ ├── NotEmpty.java │ ├── NotNull.java │ └── Validated.java ├── plugin-script ├── build_plugin.sh ├── format_json.py ├── package_plugin.sh ├── release.sh └── test.sh ├── settings.gradle.kts └── third ├── dubbo.config ├── generic.spring.demo.config ├── javax.validation.config ├── markdown.cn.config ├── swagger.advanced.config ├── swagger.config ├── swagger3.config └── template ├── api.template.md └── api.template.zh.md /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: yes 3 | 4 | coverage: 5 | precision: 3 6 | round: nearest 7 | range: "60...80" 8 | status: 9 | patch: off 10 | project: off 11 | 12 | comment: 13 | layout: "reach,diff,flags,files,footer" 14 | behavior: default 15 | require_changes: false # if true: only post the comment if coverage changes 16 | require_base: no # [yes :: must have a base report to post] 17 | require_head: no # [yes :: must have a head report to post] 18 | 19 | ignore: 20 | - ".github" 21 | - "gradle" 22 | - "script" 23 | - "**/*.sh" 24 | - "**/*.png" 25 | - "**/*.yml" 26 | - "**/*.gradle" 27 | - "**/*.md" 28 | - "**/*.properties" 29 | - "gradlew" 30 | - "gradlew.bat" 31 | - "**/*Dialog.kt" 32 | - "**/*Configurable.kt" 33 | - "**/*Action.kt" 34 | - ".*model.*" -------------------------------------------------------------------------------- /.easy.api.config: -------------------------------------------------------------------------------- 1 | # rule to export method doc 2 | api.name=groovy:it.name() 3 | mdoc.method.filter=groovy:!it.hasModifier("private") -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this plugin 4 | title: '[Feature] Xxx' 5 | labels: 'type: feature request' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: consult about features or configuration for this plugin 4 | title: '[Question] Xxx' 5 | labels: 'type: question&discussion' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the question** 11 | 12 | A clear and concise description of what the question is. 13 | 14 | **Expected result** 15 | 16 | A clear and concise description of what you expected to get. 17 | 18 | **Screenshots** 19 | 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Demo Code** 23 | 24 | 1. Fork https://github.com/Earth-1610/spring-demo 25 | 2. Write some code 26 | 3. Now paste the forked repository hear: https://github.com/xxxx/spring-demo 27 | 28 | **Additional context** 29 | 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/issue_label_bot.yaml: -------------------------------------------------------------------------------- 1 | label-alias: 2 | bug: 'bug' 3 | feature_request: 'enhancement' 4 | question: 'question' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.war 15 | *.nar 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | .gradle/ 24 | .idea/ 25 | 26 | /build 27 | /idea-plugin/build 28 | /idea-plugin/idea-sandbox/ 29 | /idea-plugin/bin/ 30 | 31 | \.DS_Store 32 | 33 | common-api/build/ 34 | 35 | /plugin/ 36 | /common-api/out/ 37 | /idea-plugin/out/ 38 | 39 | src/main/resources/META-INF/services/com.itangcent.common.spi.SetupAble 40 | 41 | /src 42 | 43 | *.iml 44 | 45 | /envs 46 | out/ 47 | 48 | gradle/wrapper/caches 49 | gradle/wrapper/daemon -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: false # faster builds 3 | 4 | matrix: 5 | include: 6 | - os: linux 7 | sudo: required 8 | jdk: openjdk8 9 | 10 | script: 11 | - ./plugin-script/package_plugin.sh 12 | 13 | before_cache: 14 | - rm -f $HOME/.gradle/caches/** 15 | 16 | cache: 17 | directories: 18 | - $HOME/.gradle/caches/ 19 | - $HOME/.gradle/wrapper/ 20 | # 21 | #before_deploy: 22 | # - git config --local user.name "tangcent" 23 | # - git config --local user.email "pentatangcent@gmail.com" 24 | # - echo jars- `ls plugin` 25 | # - ./plugin-script/push_tag.sh 26 | # - export TRAVIS_TAG=`cat tag.txt` 27 | # - export TRAVIS_TAG_TITLE=`cat title.txt` 28 | # - export TRAVIS_TAG_BODY=`cat body.txt` 29 | # 30 | ## https://github.com/travis-ci/dpl#github-releases 31 | #deploy: 32 | # provider: releases 33 | # api_key: $GITHUB_TOKEN 34 | # name: ${TRAVIS_TAG_TITLE} 35 | # body: ${TRAVIS_TAG_BODY} 36 | # file_glob: true 37 | # file: plugin/* 38 | # overwrite: true 39 | # skip_cleanup: true 40 | # on: 41 | # branch: master 42 | # repo: tangcent/easy-api 43 | -------------------------------------------------------------------------------- /assets/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangcent/easy-api/877cc45f6aa57cecdfd569b957e7caa1f31891f9/assets/close.png -------------------------------------------------------------------------------- /assets/no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangcent/easy-api/877cc45f6aa57cecdfd569b957e7caa1f31891f9/assets/no.png -------------------------------------------------------------------------------- /assets/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangcent/easy-api/877cc45f6aa57cecdfd569b957e7caa1f31891f9/assets/ok.png -------------------------------------------------------------------------------- /assets/reset.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /assets/yes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangcent/easy-api/877cc45f6aa57cecdfd569b957e7caa1f31891f9/assets/yes.png -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/annotation/script/ScriptIgnore.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.annotation.script 2 | 3 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) 4 | @Retention(AnnotationRetention.RUNTIME) 5 | annotation class ScriptIgnore(vararg val name: String = []) -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/annotation/script/ScriptReturn.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.annotation.script 2 | 3 | @Target(AnnotationTarget.FUNCTION) 4 | @Retention(AnnotationRetention.RUNTIME) 5 | annotation class ScriptReturn(val name: String) -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/annotation/script/ScriptTypeName.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.annotation.script 2 | 3 | @Target(AnnotationTarget.CLASS) 4 | @Retention(AnnotationRetention.RUNTIME) 5 | annotation class ScriptTypeName(val name: String) -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/annotation/script/ScriptUnIgnore.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.annotation.script 2 | 3 | @Target(AnnotationTarget.FUNCTION) 4 | @Retention(AnnotationRetention.RUNTIME) 5 | annotation class ScriptUnIgnore -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/common/constant/Attrs.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.common.constant 2 | 3 | object Attrs { 4 | 5 | const val COMMENT_ATTR = "@comment" 6 | 7 | const val REQUIRED_ATTR = "@required" 8 | 9 | const val DEFAULT_VALUE_ATTR = "@default" 10 | 11 | const val DEMO_ATTR = "@demo" 12 | 13 | const val PREFIX = "@" 14 | 15 | val ALL = arrayOf(COMMENT_ATTR, REQUIRED_ATTR, DEFAULT_VALUE_ATTR) 16 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/common/constant/HttpMethod.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.common.constant 2 | 3 | object HttpMethod { 4 | const val NO_METHOD = "ALL" 5 | const val GET = "GET" 6 | const val POST = "POST" 7 | const val DELETE = "DELETE" 8 | const val PUT = "PUT" 9 | const val PATCH = "PATCH" 10 | const val OPTIONS = "OPTIONS" 11 | const val TRACE = "TRACE" 12 | const val HEAD = "HEAD" 13 | 14 | val ALL_METHODS = arrayOf(GET, POST, DELETE, PUT, 15 | PATCH, OPTIONS, TRACE, HEAD) 16 | 17 | /** 18 | * fix method to match the standard 19 | */ 20 | fun preferMethod(method: String): String { 21 | if (method.isBlank()) { 22 | return NO_METHOD 23 | } 24 | val standardMethod = method.uppercase() 25 | if (ALL_METHODS.contains(standardMethod)) { 26 | return standardMethod 27 | } 28 | for (me in ALL_METHODS) { 29 | if (standardMethod.contains(".$me")) { 30 | return me 31 | } 32 | } 33 | for (me in ALL_METHODS) { 34 | if (standardMethod.contains(me)) { 35 | return me 36 | } 37 | } 38 | return NO_METHOD 39 | } 40 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/common/http/EntityUtils.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.common.http 2 | 3 | import java.util.* 4 | 5 | object EntityUtils { 6 | 7 | /** 8 | * The pool of ASCII chars to be used for generating a multipart boundary. 9 | */ 10 | private val MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 11 | .toCharArray() 12 | 13 | /** 14 | * @see org.apache.http.entity.mime.MultipartEntity#generateBoundary 15 | */ 16 | fun generateBoundary(): String { 17 | val buffer = StringBuilder() 18 | val rand = Random() 19 | val count = rand.nextInt(11) + 30 // a random size from 30 to 40 20 | for (i in 0 until count) { 21 | buffer.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.size)]) 22 | } 23 | return buffer.toString() 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/common/kit/KitUtils.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.common.kit 2 | 3 | import com.itangcent.common.spi.SpiUtils 4 | import com.itangcent.utils.DefaultJsonSupport 5 | import com.itangcent.utils.JsonSupport 6 | 7 | private val jsonSupport by lazy { SpiUtils.loadService(JsonSupport::class) ?: DefaultJsonSupport } 8 | 9 | fun Any?.toJson(): String? { 10 | if (this == null) { 11 | return null 12 | } 13 | 14 | if (this is String) { 15 | return this 16 | } 17 | return jsonSupport.toJson(this) 18 | } 19 | 20 | fun String.headLine(): String? { 21 | if (this.isBlank()) return null 22 | 23 | var index = -1 24 | val trimStr = this.trim() 25 | for ((i, c) in trimStr.withIndex()) { 26 | if (c == '\r' || c == '\n') { 27 | index = i 28 | break 29 | } 30 | } 31 | if (index == -1) { 32 | return this 33 | } 34 | return trimStr.substring(0, index) 35 | } 36 | 37 | fun String?.equalIgnoreCase(str: String?): Boolean { 38 | return this.equals(str, ignoreCase = true) 39 | } 40 | -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/common/kit/StreamKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.common.kit 2 | 3 | -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/common/model/Doc.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.common.model 2 | 3 | import com.itangcent.common.utils.SimpleExtensible 4 | import com.google.gson.annotations.Expose 5 | import java.io.Serializable 6 | 7 | /** 8 | * Instances of the [Doc] represent a document(Http or RPC) in the project. 9 | */ 10 | open class Doc : SimpleExtensible(), Serializable { 11 | 12 | /** 13 | * The element associated the origin code. 14 | */ 15 | @Transient 16 | @Expose(serialize = false, deserialize = false) 17 | var resource: Any? = null 18 | 19 | /** 20 | * Returns the name of the doc. 21 | */ 22 | var name: String? = null 23 | 24 | /** 25 | * Returns the description of the doc. 26 | * Explain what this document represented in a human readable way. 27 | */ 28 | var desc: String? = null 29 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/common/model/MethodDoc.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.common.model 2 | 3 | /** 4 | * MethodDoc represents a document generated by a Java method that may not include any HTTP request. 5 | * In general it could be an RPC interface. 6 | */ 7 | class MethodDoc : Doc() { 8 | 9 | var params: MutableList? = null 10 | 11 | var ret: Any? = null 12 | 13 | var retDesc: String? = null 14 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/common/model/NamedValue.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.common.model 2 | 3 | /** 4 | * Interface for objects that have a name and value. 5 | */ 6 | interface NamedValue { 7 | /** 8 | * The name of this value. 9 | */ 10 | var name: String? 11 | 12 | /** 13 | * The value. 14 | */ 15 | var value: T? 16 | } 17 | 18 | 19 | fun > List.find(name: String): T? { 20 | return this.firstOrNull { it.name == name } 21 | } 22 | 23 | fun > List.findIgnoreCase(name: String): T? { 24 | return this.firstOrNull { it.name?.equals(name, ignoreCase = true) == true } 25 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/common/model/PathParam.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.common.model 2 | 3 | import com.itangcent.common.utils.SimpleExtensible 4 | import java.io.Serializable 5 | 6 | class PathParam : SimpleExtensible(), NamedValue, Serializable { 7 | override var name: String? = null 8 | 9 | override var value: String? = null 10 | 11 | var desc: String? = null 12 | 13 | override fun equals(other: Any?): Boolean { 14 | if (this === other) return true 15 | if (javaClass != other?.javaClass) return false 16 | 17 | other as PathParam 18 | 19 | if (name != other.name) return false 20 | if (value != other.value) return false 21 | if (desc != other.desc) return false 22 | 23 | return true 24 | } 25 | 26 | override fun hashCode(): Int { 27 | var result = name?.hashCode() ?: 0 28 | result = 31 * result + (value?.hashCode() ?: 0) 29 | result = 31 * result + (desc?.hashCode() ?: 0) 30 | return result 31 | } 32 | 33 | override fun toString(): String { 34 | return "PathParam(name=$name, value=$value, desc=$desc)" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/http/RawContentType.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.http 2 | 3 | import org.apache.http.entity.ContentType 4 | 5 | /** 6 | * define raw content types without charset 7 | * 8 | * @author tangcent 9 | * @date 2024/06/29 10 | */ 11 | object RawContentType { 12 | 13 | val APPLICATION_JSON = ContentType.create("application/json")!! 14 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/utils/ActionKeys.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | /** 4 | * Event keys for inner action completion 5 | */ 6 | object ActionKeys { 7 | /** 8 | * Event key for when an inner action is completed. 9 | * Listeners can use this to perform cleanup operations (e.g. clear caches) 10 | * but should remain active for future actions. 11 | */ 12 | const val ACTION_COMPLETED = "com.itangcent.action.completed" 13 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/utils/DefaultJsonSupport.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | import com.itangcent.common.utils.GsonUtils 4 | 5 | object DefaultJsonSupport : JsonSupport { 6 | override fun toJson(obj: Any?): String { 7 | return GsonUtils.toJson(obj) 8 | } 9 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/utils/FuncKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | 4 | fun ((T) -> Boolean).and(next: (T) -> Boolean): (T) -> Boolean { 5 | return { this(it) && next(it) } 6 | } 7 | 8 | fun ((T) -> Unit).then(next: (T) -> Unit): (T) -> Unit { 9 | return { 10 | this(it) 11 | next(it) 12 | } 13 | } 14 | 15 | fun ((T, T1, T2) -> Unit).then(next: (T, T1, T2) -> Unit): (T, T1, T2) -> Unit { 16 | return { t, t1, t2 -> 17 | this(t, t1, t2) 18 | next(t, t1, t2) 19 | } 20 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/utils/JsonSupport.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | interface JsonSupport { 4 | 5 | fun toJson(obj: Any?): String 6 | 7 | } -------------------------------------------------------------------------------- /common-api/src/main/kotlin/com/itangcent/utils/KClassKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | import kotlin.reflect.KClass 4 | import kotlin.reflect.full.allSuperclasses 5 | 6 | fun KClass<*>.superClasses(handle: (KClass<*>) -> Unit) { 7 | handle(this) 8 | this.allSuperclasses.forEach(handle) 9 | } -------------------------------------------------------------------------------- /common-api/src/test/kotlin/com/itangcent/common/http/EntityUtilsTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.common.http 2 | 3 | import org.junit.jupiter.api.Assertions.assertNotNull 4 | import org.junit.jupiter.api.Assertions.assertTrue 5 | import org.junit.jupiter.api.Test 6 | 7 | internal class EntityUtilsTest { 8 | 9 | @Test 10 | fun generateBoundary() { 11 | val set = HashSet() 12 | for (i in 0..100) { 13 | val boundary = EntityUtils.generateBoundary() 14 | assertNotNull(boundary) 15 | //length of boundary should be a random size from 30 to 40 16 | assertTrue(boundary.length >= 30) 17 | assertTrue(boundary.length <= 40) 18 | assertTrue(set.add(boundary)) 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /common-api/src/test/kotlin/com/itangcent/http/BasicHttpHeaderTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.http 2 | 3 | import org.junit.jupiter.api.Test 4 | import kotlin.test.assertEquals 5 | 6 | /** 7 | * Test case of [BasicHttpHeader] 8 | */ 9 | internal class BasicHttpHeaderTest { 10 | @Test 11 | fun testNameAndValue() { 12 | val header = BasicHttpHeader("name", "value") 13 | assertEquals("name", header.name()) 14 | assertEquals("value", header.value()) 15 | } 16 | 17 | @Test 18 | fun testSetNameAndValue() { 19 | val header = BasicHttpHeader() 20 | header.setName("name") 21 | header.setValue("value") 22 | assertEquals("name", header.name()) 23 | assertEquals("value", header.value()) 24 | } 25 | } -------------------------------------------------------------------------------- /common-api/src/test/kotlin/com/itangcent/http/BasicHttpParamTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.http 2 | 3 | import org.junit.jupiter.api.Test 4 | import kotlin.test.assertEquals 5 | 6 | /** 7 | * Test case of [BasicHttpParam] 8 | */ 9 | internal class BasicHttpParamTest { 10 | 11 | @Test 12 | fun testHttpParam() { 13 | val param = BasicHttpParam("name", "value", "file") 14 | assertEquals("name", param.name()) 15 | assertEquals("value", param.value()) 16 | assertEquals("file", param.type()) 17 | 18 | val param2 = BasicHttpParam("name", "value") 19 | assertEquals("name", param2.name()) 20 | assertEquals("value", param2.value()) 21 | assertEquals("text", param2.type()) 22 | } 23 | 24 | @Test 25 | fun testSetters() { 26 | val param = BasicHttpParam() 27 | param.setName("name") 28 | param.setValue("value") 29 | param.setType("file") 30 | assertEquals("name", param.name()) 31 | assertEquals("value", param.value()) 32 | assertEquals("file", param.type()) 33 | } 34 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | plugin_name=EasyApi 2 | plugin_version=2.4.1.212.0 3 | kotlin.code.style=official 4 | kotlin_version=2.1.0 5 | junit_version=5.9.2 6 | itangcent_intellij_version=1.7.7 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangcent/easy-api/877cc45f6aa57cecdfd569b957e7caa1f31891f9/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /idea-plugin/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | kotlin.daemon.jvmargs=-Xmx2G -------------------------------------------------------------------------------- /idea-plugin/parts/pluginChanges.html: -------------------------------------------------------------------------------- 1 | v2.4.1(2025-04-21)
2 | Full Changelog 3 | 4 |

Enhancements:

5 | 6 |
    7 |
  • feat: Enhance script object 'api' with parameter accessor methods (#604)
  • 8 | 9 |
  • feat: Add multi-window console logging capability (#600)
  • 10 | 11 |
  • feat: ignore fields from java.lang system classes to prevent complex exported types (#598)
  • 12 |
13 | 14 |

Fixes:

15 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/ai/AIException.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.ai 2 | 3 | /** 4 | * Base exception for all AI-related errors 5 | */ 6 | open class AIException(message: String, cause: Throwable? = null) : RuntimeException(message, cause) 7 | 8 | /** 9 | * Exception thrown when there's an issue with the AI service configuration 10 | */ 11 | class AIConfigurationException(message: String) : AIException(message) 12 | 13 | /** 14 | * Exception thrown when there's an error in the AI service API response 15 | */ 16 | class AIApiException(message: String, cause: Throwable? = null) : AIException(message, cause) -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/ai/AIMessages.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.ai 2 | 3 | /** 4 | * Contains messages used by AI services 5 | */ 6 | object AIMessages { 7 | /** 8 | * Default system message for general code-related tasks 9 | */ 10 | const val DEFAULT_SYSTEM_MESSAGE = 11 | "You are a helpful programming assistant with expertise in Java, Kotlin, and related technologies. " + 12 | "You can assist with code understanding, debugging, refactoring, optimization, and design. " + 13 | "Analyze the provided code and context carefully, and provide clear, accurate, and practical responses. " + 14 | "When appropriate, suggest improvements while respecting the existing code structure and patterns." 15 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/cache/HttpContextCacheHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.cache 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.itangcent.http.Cookie 5 | 6 | @ImplementedBy(DefaultHttpContextCacheHelper::class) 7 | interface HttpContextCacheHelper { 8 | 9 | fun getHosts(): List 10 | 11 | fun addHost(host: String) 12 | 13 | fun getCookies(): List 14 | 15 | fun addCookies(cookies: List) 16 | 17 | fun selectHost(message: String? = null): String 18 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/condition/Condition.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.condition 2 | 3 | import com.itangcent.intellij.context.ActionContext 4 | import kotlin.reflect.KClass 5 | 6 | /** 7 | * A single condition that must be matched in order for a bean to be loaded. 8 | * Conditions are checked immediately before create the instance of the bean. 9 | */ 10 | interface Condition { 11 | 12 | /** 13 | * Determine if the condition matches. 14 | * @param actionContext the action context of current Action 15 | * @param beanClass class of the bean being checked 16 | * @return {@code true} if the condition matches and the bean can be loaded 17 | */ 18 | fun matches(actionContext: ActionContext, beanClass: KClass<*>): Boolean 19 | } 20 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/condition/ConditionEvaluator.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.condition 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.itangcent.intellij.context.ActionContext 5 | import kotlin.reflect.KClass 6 | 7 | @ImplementedBy(DefaultConditionEvaluator::class) 8 | interface ConditionEvaluator { 9 | 10 | fun matches(actionContext: ActionContext, beanClass: KClass<*>): Boolean 11 | } 12 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/condition/ConditionSupported.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.condition 2 | 3 | import kotlin.reflect.KClass 4 | 5 | interface ConditionSupported { 6 | 7 | fun supported(beanClass: KClass<*>): Boolean 8 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/condition/Conditional.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.condition 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * Indicates that a bean is only eligible for loaded when all specified conditions match. 7 | */ 8 | @Target(AnnotationTarget.CLASS) 9 | @Retention(AnnotationRetention.RUNTIME) 10 | annotation class Conditional(vararg val value: KClass) 11 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/condition/Exclusion.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.condition 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * If current class be loaded, Exclude specific classes such that they will never be loaded. 7 | */ 8 | @Target(AnnotationTarget.CLASS) 9 | @Retention(AnnotationRetention.RUNTIME) 10 | annotation class Exclusion(vararg val value: KClass<*>) 11 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/debug/LoggerCollector.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.debug 2 | 3 | import com.itangcent.debug.LoggerCollector.Companion.buffer 4 | import com.itangcent.intellij.logger.Level 5 | import com.itangcent.intellij.logger.Logger 6 | 7 | /** 8 | * 9 | * This interface represents [Logger] which collect all appended logs to a buffer. 10 | */ 11 | class LoggerCollector : Logger { 12 | 13 | override fun log(level: Level, msg: String) { 14 | buffer.append("[${level.name}]\t$msg").appendLine() 15 | } 16 | 17 | companion object { 18 | 19 | /** 20 | * Cache logs which be added by [LoggerCollector.log]. 21 | */ 22 | private val buffer: StringBuilder = StringBuilder() 23 | 24 | /** 25 | * Get log in [buffer]. 26 | * The [buffer] will be clear after return. 27 | * 28 | * @return all log in [buffer] 29 | */ 30 | fun getLog(): String { 31 | val str = buffer.toString() 32 | buffer.clear() 33 | return str 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/condition/OnClassCondition.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.condition 2 | 3 | import com.intellij.openapi.project.Project 4 | import com.itangcent.condition.AnnotatedCondition 5 | import com.itangcent.idea.condition.annotation.ConditionOnClass 6 | import com.itangcent.idea.psi.PsiClassFinder 7 | import com.itangcent.intellij.context.ActionContext 8 | 9 | /** 10 | * Condition that checks for [ConditionOnClass]. 11 | */ 12 | class OnClassCondition : AnnotatedCondition() { 13 | 14 | override fun matches(actionContext: ActionContext, annotation: ConditionOnClass): Boolean { 15 | val project = actionContext.instance(Project::class) 16 | return actionContext.callInReadUI { 17 | return@callInReadUI annotation.value.all { 18 | PsiClassFinder.findClass(it, project) != null 19 | } 20 | } ?: false 21 | } 22 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/condition/OnMissingClassCondition.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.condition 2 | 3 | import com.intellij.openapi.project.Project 4 | import com.itangcent.condition.AnnotatedCondition 5 | import com.itangcent.idea.condition.annotation.ConditionOnMissingClass 6 | import com.itangcent.idea.psi.PsiClassFinder 7 | import com.itangcent.intellij.context.ActionContext 8 | 9 | /** 10 | * Condition that checks for [ConditionOnMissingClass]. 11 | */ 12 | class OnMissingClassCondition : AnnotatedCondition() { 13 | 14 | override fun matches(actionContext: ActionContext, annotation: ConditionOnMissingClass): Boolean { 15 | val project = actionContext.instance(Project::class) 16 | return actionContext.callInReadUI { 17 | return@callInReadUI annotation.value.all { 18 | PsiClassFinder.findClass(it, project) == null 19 | } 20 | } ?: false 21 | } 22 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/condition/annotation/ConditionOnClass.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.condition.annotation 2 | 3 | /** 4 | * Conditional that only matches when the specified classes be found in current project. 5 | */ 6 | @Target(AnnotationTarget.CLASS) 7 | @Retention(AnnotationRetention.RUNTIME) 8 | annotation class ConditionOnClass(vararg val value: String) -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/condition/annotation/ConditionOnMissingClass.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.condition.annotation 2 | 3 | /** 4 | * Conditional that only matches when the specified classes not be found in current project. 5 | */ 6 | @Target(AnnotationTarget.CLASS) 7 | @Retention(AnnotationRetention.RUNTIME) 8 | annotation class ConditionOnMissingClass(vararg val value: String) -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/CustomInfoImpl.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin 2 | 3 | import com.itangcent.intellij.CustomInfo 4 | 5 | class CustomInfoImpl : CustomInfo { 6 | override fun pluginName(): String { 7 | return "easy-api" 8 | } 9 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/Initializer.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin 2 | 3 | interface Initializer { 4 | fun init(); 5 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/FieldsToJson5Action.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.actions 2 | 3 | import com.google.inject.Inject 4 | import com.intellij.psi.PsiClass 5 | import com.intellij.psi.PsiType 6 | import com.itangcent.idea.plugin.format.Json5Formatter 7 | import com.itangcent.intellij.context.ActionContext 8 | import com.itangcent.intellij.jvm.PsiClassHelper 9 | import com.itangcent.intellij.jvm.JsonOption 10 | 11 | /** 12 | * @author tangcent 13 | */ 14 | class FieldsToJson5Action : FieldsToMessageAction("To Json5") { 15 | 16 | @Inject 17 | private val psiClassHelper: PsiClassHelper? = null 18 | 19 | override fun actionName(): String { 20 | return "FieldsToJson5Action" 21 | } 22 | 23 | override fun formatMessage(psiClass: PsiClass, type: PsiType?): String { 24 | val obj = psiClassHelper!!.getTypeObject( 25 | psiType = type, 26 | context = psiClass, 27 | option = JsonOption.ALL 28 | ) 29 | return ActionContext.getContext()!!.instance(Json5Formatter::class).format(obj) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/FieldsToJsonAction.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.actions 2 | 3 | import com.google.inject.Inject 4 | import com.intellij.psi.PsiClass 5 | import com.intellij.psi.PsiType 6 | import com.itangcent.idea.plugin.format.SimpleJsonFormatter 7 | import com.itangcent.intellij.context.ActionContext 8 | import com.itangcent.intellij.jvm.JsonOption 9 | import com.itangcent.intellij.jvm.PsiClassHelper 10 | 11 | /** 12 | * @author tangcent 13 | */ 14 | class FieldsToJsonAction : FieldsToMessageAction("To Json") { 15 | 16 | @Inject 17 | private val psiClassHelper: PsiClassHelper? = null 18 | 19 | override fun actionName(): String { 20 | return "FieldsToJsonAction" 21 | } 22 | 23 | override fun formatMessage(psiClass: PsiClass, type: PsiType?): String { 24 | val obj = psiClassHelper!!.getTypeObject( 25 | psiType = type, 26 | context = psiClass, 27 | option = JsonOption.READ_GETTER or JsonOption.READ_SETTER 28 | ) 29 | return ActionContext.getContext()!!.instance(SimpleJsonFormatter::class).format(obj) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/cache/FileApiCacheRepository.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.cache 2 | 3 | import com.google.inject.ImplementedBy 4 | 5 | @ImplementedBy(DefaultFileApiCacheRepository::class) 6 | interface FileApiCacheRepository { 7 | 8 | fun getFileApiCache(filePath: String): FileApiCache? 9 | 10 | fun saveFileApiCache(filePath: String, fileApiCache: FileApiCache) 11 | 12 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/cache/ProjectCacheRepository.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.cache 2 | 3 | import com.google.inject.Inject 4 | import com.google.inject.Singleton 5 | import com.intellij.openapi.project.Project 6 | import com.itangcent.intellij.context.ActionContext 7 | import com.itangcent.intellij.file.AbstractLocalFileRepository 8 | import java.io.File 9 | 10 | @Singleton 11 | class ProjectCacheRepository : AbstractLocalFileRepository() { 12 | 13 | @Inject 14 | private val project: Project? = null 15 | 16 | @Inject 17 | private val actionContext: ActionContext? = null 18 | 19 | override fun basePath(): String { 20 | val basePath = actionContext!!.cacheOrCompute("project_path") { project!!.basePath } 21 | return basePath!! + "${File.separator}.idea${File.separator}.cache" 22 | } 23 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/ExportChannel.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export 2 | 3 | interface ExportChannel { 4 | fun channel(): String? 5 | 6 | companion object { 7 | fun of(channel: String): ExportChannel { 8 | return SimpleExportChannel(channel) 9 | } 10 | } 11 | } 12 | 13 | 14 | private class SimpleExportChannel(val channel: String) : ExportChannel { 15 | override fun channel(): String { 16 | return channel 17 | } 18 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/ExportDoc.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export 2 | 3 | interface ExportDoc { 4 | 5 | fun doc(): Array? 6 | 7 | companion object { 8 | 9 | @Suppress("UNCHECKED_CAST") 10 | fun of(vararg channel: String): ExportDoc { 11 | return SimpleExportDoc(channel as Array) 12 | } 13 | } 14 | } 15 | 16 | 17 | private class SimpleExportDoc(val doc: Array) : ExportDoc { 18 | override fun doc(): Array { 19 | return doc 20 | } 21 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/Orders.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export 2 | 3 | object Orders { 4 | 5 | const val GENERIC = 10000 6 | 7 | const val METHOD_DOC = 100 8 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/condition/ConditionOnChannel.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.condition 2 | 3 | /** 4 | * Conditional that only matches when exporting to the specified channel. 5 | * @param value postman/yapi/markdown 6 | */ 7 | @Target(AnnotationTarget.CLASS) 8 | @Retention(AnnotationRetention.RUNTIME) 9 | annotation class ConditionOnChannel(vararg val value: String) 10 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/condition/ConditionOnDoc.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.condition 2 | 3 | /** 4 | * Conditional that only matches when exporting the specified type of docs. 5 | * @param value request/methodDoc 6 | */ 7 | @Target(AnnotationTarget.CLASS) 8 | @Retention(AnnotationRetention.RUNTIME) 9 | annotation class ConditionOnDoc(vararg val value:String) 10 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/condition/ConditionOnSimple.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.condition 2 | 3 | import com.itangcent.idea.plugin.api.export.condition.ConditionOnSimple.Companion.CACHE_NAME 4 | import com.itangcent.intellij.context.ActionContext 5 | import com.itangcent.intellij.context.ActionContextBuilder 6 | 7 | /** 8 | * Conditional that only matches when the [CACHE_NAME] cached in the actionContext equals the given [value]. 9 | * @param value true/false 10 | */ 11 | @Target(AnnotationTarget.CLASS) 12 | @Retention(AnnotationRetention.RUNTIME) 13 | annotation class ConditionOnSimple(val value: Boolean = true) { 14 | companion object { 15 | const val CACHE_NAME = "is_simple" 16 | } 17 | } 18 | 19 | fun ActionContext.markAsSimple() { 20 | this.cache(CACHE_NAME, true) 21 | } 22 | 23 | fun ActionContextBuilder.markAsSimple() { 24 | this.cache(CACHE_NAME, true) 25 | } 26 | 27 | fun ActionContext.markSimple(value: Boolean) { 28 | this.cache(CACHE_NAME, value) 29 | } 30 | 31 | fun ActionContextBuilder.markSimple(value: Boolean) { 32 | this.cache(CACHE_NAME, value) 33 | } 34 | 35 | fun ActionContext.isSimple(): Boolean { 36 | return this.getCache(CACHE_NAME) ?: false 37 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/condition/OnChannelCondition.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.condition 2 | 3 | import com.itangcent.condition.AnnotatedCondition 4 | import com.itangcent.idea.plugin.api.export.ExportChannel 5 | import com.itangcent.intellij.context.ActionContext 6 | 7 | /** 8 | * Condition that checks for [ConditionOnChannel]. 9 | */ 10 | class OnChannelCondition : AnnotatedCondition() { 11 | 12 | override fun matches(actionContext: ActionContext, annotation: ConditionOnChannel): Boolean { 13 | val exportChannel = try { 14 | actionContext.instance(ExportChannel::class).channel() ?: return false 15 | } catch (e: Exception) { 16 | return false 17 | } 18 | return annotation.value.contains(exportChannel) 19 | } 20 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/condition/OnDocCondition.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.condition 2 | 3 | import com.itangcent.condition.AnnotatedCondition 4 | import com.itangcent.idea.plugin.api.export.ExportDoc 5 | import com.itangcent.intellij.context.ActionContext 6 | 7 | /** 8 | * Condition that checks for [ConditionOnDoc]. 9 | */ 10 | class OnDocCondition : AnnotatedCondition() { 11 | 12 | override fun matches(actionContext: ActionContext, annotation: ConditionOnDoc): Boolean { 13 | val exportDoc = try { 14 | actionContext.instance(ExportDoc::class).doc() ?: return false 15 | } catch (e: Exception) { 16 | return false 17 | } 18 | return annotation.value.any { exportDoc.contains(it) } 19 | } 20 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/condition/OnSimpleCondition.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.condition 2 | 3 | import com.itangcent.condition.AnnotatedCondition 4 | import com.itangcent.intellij.context.ActionContext 5 | 6 | /** 7 | * Condition that checks for [ConditionOnSimple]. 8 | */ 9 | class OnSimpleCondition : AnnotatedCondition() { 10 | 11 | override fun matches(actionContext: ActionContext, annotation: ConditionOnSimple): Boolean { 12 | return actionContext.isSimple() == annotation.value 13 | } 14 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/AdditionalParseHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.itangcent.common.model.Header 5 | import com.itangcent.common.model.Param 6 | import com.itangcent.idea.plugin.api.export.AdditionalField 7 | 8 | @ImplementedBy(DefaultAdditionalParseHelper::class) 9 | interface AdditionalParseHelper { 10 | 11 | fun parseHeaderFromJson(headerStr: String): Header 12 | 13 | fun parseParamFromJson(paramStr: String): Param 14 | 15 | fun parseFieldFromJson(paramStr: String): AdditionalField 16 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/ClassExporter.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.itangcent.common.model.Doc 5 | import com.itangcent.common.model.MethodDoc 6 | import com.itangcent.common.model.Request 7 | import kotlin.reflect.KClass 8 | 9 | @ImplementedBy(DefaultClassExporter::class) 10 | interface ClassExporter { 11 | 12 | /** 13 | * @return return true if this ClassExporter can parse the cls 14 | */ 15 | fun export(cls: Any, docHandle: DocHandle): Boolean 16 | 17 | /** 18 | * the document type which be generate 19 | */ 20 | fun support(docType: KClass<*>): Boolean 21 | } 22 | 23 | typealias DocHandle = (Doc) -> Unit 24 | 25 | inline fun requestOnly(crossinline requestHandle: ((Request) -> Unit)): DocHandle { 26 | return { 27 | if (it is Request) { 28 | requestHandle(it) 29 | } 30 | } 31 | } 32 | 33 | inline fun methodDocOnly(crossinline methodDocHandle: ((MethodDoc) -> Unit)): DocHandle { 34 | return { 35 | if (it is MethodDoc) { 36 | methodDocHandle(it) 37 | } 38 | } 39 | } 40 | 41 | inline fun docs(crossinline docHandle: DocHandle): DocHandle { 42 | return { 43 | docHandle(it) 44 | } 45 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/DefaultAdditionalParseHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.google.inject.Singleton 4 | import com.itangcent.common.model.Header 5 | import com.itangcent.common.model.Param 6 | import com.itangcent.idea.plugin.api.export.AdditionalField 7 | import com.itangcent.utils.ExtensibleKit.fromJson 8 | 9 | @Singleton 10 | class DefaultAdditionalParseHelper : AdditionalParseHelper { 11 | 12 | override fun parseHeaderFromJson(headerStr: String): Header = Header::class.fromJson(headerStr) 13 | 14 | override fun parseParamFromJson(paramStr: String): Param = Param::class.fromJson(paramStr) 15 | 16 | override fun parseFieldFromJson(paramStr: String): AdditionalField = AdditionalField::class.fromJson(paramStr) 17 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/DefaultClassExporter.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.google.inject.Inject 4 | import com.google.inject.Singleton 5 | import com.itangcent.intellij.context.ActionContext 6 | import com.itangcent.spi.SpiCompositeLoader 7 | import kotlin.reflect.KClass 8 | 9 | @Singleton 10 | class DefaultClassExporter : ClassExporter { 11 | 12 | @Inject 13 | private lateinit var actionContext: ActionContext 14 | 15 | private val subClassExporters: Array by lazy { 16 | SpiCompositeLoader.load(actionContext) 17 | } 18 | 19 | override fun support(docType: KClass<*>): Boolean { 20 | return this.subClassExporters.any { it.support(docType) } 21 | } 22 | 23 | override fun export(cls: Any, docHandle: DocHandle): Boolean { 24 | return this.subClassExporters.any { it.export(cls, docHandle) } 25 | } 26 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/DocParseHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.intellij.psi.PsiMember 5 | import com.itangcent.idea.plugin.api.export.core.DefaultDocParseHelper 6 | 7 | @ImplementedBy(DefaultDocParseHelper::class) 8 | interface DocParseHelper { 9 | fun resolveLinkInAttr(attr: String?, psiMember: PsiMember): String? 10 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigProvider.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.itangcent.intellij.config.LocalFileSearchConfigProvider 4 | import com.itangcent.order.Order 5 | import com.itangcent.order.Ordered 6 | 7 | @Order(Ordered.HIGHEST_PRECEDENCE) 8 | class EasyApiConfigProvider : LocalFileSearchConfigProvider() { 9 | 10 | override fun configFileNames(): List { 11 | return listOf( 12 | ".easy.api.config", 13 | ".easy.api.yml", 14 | ".easy.api.yaml" 15 | ) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/Folder.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.itangcent.common.utils.SimpleExtensible 4 | 5 | class Folder : SimpleExtensible { 6 | 7 | val name: String? 8 | 9 | val attr: String? 10 | 11 | constructor(name: String?) { 12 | this.name = name?.trim() 13 | this.attr = null 14 | } 15 | 16 | constructor(name: String?, attr: String?) { 17 | this.name = name?.trim() 18 | this.attr = attr 19 | } 20 | 21 | override fun equals(other: Any?): Boolean { 22 | if (this === other) return true 23 | if (javaClass != other?.javaClass) return false 24 | 25 | other as Folder 26 | 27 | if (name != other.name) return false 28 | if (attr != other.attr) return false 29 | 30 | return true 31 | } 32 | 33 | override fun hashCode(): Int { 34 | var result = name?.hashCode() ?: 0 35 | result = 31 * result + (attr?.hashCode() ?: 0) 36 | return result 37 | } 38 | 39 | override fun toString(): String { 40 | return "Folder(name=$name, attr=$attr)" 41 | } 42 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/FormatFolderHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.google.inject.ImplementedBy 4 | 5 | @ImplementedBy(DefaultFormatFolderHelper::class) 6 | interface FormatFolderHelper { 7 | 8 | fun resolveFolder(resource: Any): Folder 9 | 10 | } 11 | 12 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/LinkResolver.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.itangcent.idea.plugin.api.export.core.DefaultLinkResolver 5 | 6 | @ImplementedBy(DefaultLinkResolver::class) 7 | interface LinkResolver { 8 | 9 | fun linkToClass(linkClass: Any): String? 10 | 11 | fun linkToMethod(linkMethod: Any): String? 12 | 13 | fun linkToProperty(linkField: Any): String? 14 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/ResolveMultiPath.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.itangcent.common.model.URL 4 | import com.itangcent.common.utils.longest 5 | import com.itangcent.common.utils.shortest 6 | 7 | /** 8 | * This enumeration defines strategies to resolve multiple URLs to a single URL, 9 | * based on different criteria like the first URL, last URL, longest URL, or shortest URL. 10 | * It also provides a strategy to return all URLs as-is without any resolution. 11 | */ 12 | enum class ResolveMultiPath { 13 | FIRST { 14 | override fun resolve(url: URL): URL = URL.of(url.urls().firstOrNull()) 15 | }, 16 | LAST { 17 | override fun resolve(url: URL): URL = URL.of(url.urls().lastOrNull()) 18 | }, 19 | LONGEST { 20 | override fun resolve(url: URL): URL = URL.of(url.urls().longest()) 21 | }, 22 | SHORTEST { 23 | override fun resolve(url: URL): URL = URL.of(url.urls().shortest()) 24 | }, 25 | ALL { 26 | override fun resolve(url: URL): URL = url 27 | }; 28 | 29 | /** 30 | * resolve the given URL based on the implemented strategy 31 | */ 32 | abstract fun resolve(url: URL): URL 33 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/feign/SimpleFeignRequestClassExporter.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.feign 2 | 3 | import com.google.inject.Singleton 4 | import com.intellij.psi.PsiClass 5 | import com.itangcent.idea.condition.annotation.ConditionOnClass 6 | import com.itangcent.idea.plugin.api.export.core.ClassExportRuleKeys 7 | import com.itangcent.idea.plugin.api.export.spring.SimpleSpringRequestClassExporter 8 | import com.itangcent.idea.plugin.condition.ConditionOnSetting 9 | 10 | /** 11 | * Support export apis (name only) from client that annotated with @FeignClient 12 | * 13 | * @author tangcent 14 | */ 15 | @Singleton 16 | @ConditionOnClass(SpringFeignClassName.REQUEST_LINE_ANNOTATION) 17 | @ConditionOnSetting("feignEnable") 18 | open class SimpleFeignRequestClassExporter : SimpleSpringRequestClassExporter() { 19 | 20 | override fun isCtrl(psiClass: PsiClass): Boolean { 21 | return annotationHelper!!.hasAnn(psiClass, SpringFeignClassName.FEIGN_CLIENT_ANNOTATION) 22 | || (ruleComputer.computer(ClassExportRuleKeys.IS_FEIGN_CTRL, psiClass) ?: false) 23 | } 24 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/feign/SpringFeignClassName.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.feign 2 | 3 | 4 | object SpringFeignClassName { 5 | 6 | const val FEIGN_CLIENT_ANNOTATION = "org.springframework.cloud.openfeign.FeignClient" 7 | 8 | const val REQUEST_LINE_ANNOTATION = "feign.RequestLine" 9 | 10 | const val HEADERS_ANNOTATION = "feign.Headers" 11 | 12 | const val PARAM_ANNOTATION = "feign.Param" 13 | 14 | const val BODY_ANNOTATION = "feign.Body" 15 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/markdown/MarkdownEscapeUtils.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.markdown 2 | 3 | /** 4 | * Utility class for escaping markdown special characters in tables 5 | */ 6 | object MarkdownEscapeUtils { 7 | /** 8 | * Escapes special markdown characters in table cells 9 | * @param text The text to escape 10 | * @return The escaped text 11 | */ 12 | fun escape(text: String?): String { 13 | if (text.isNullOrBlank()) return "" 14 | 15 | return text.replace("\n", "
") 16 | .replace("|", "\\|") 17 | } 18 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/markdown/MarkdownFormatter.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.markdown 2 | 3 | import com.google.inject.ProvidedBy 4 | import com.itangcent.common.model.Doc 5 | 6 | /** 7 | * format [com.itangcent.common.model.Doc] to `markdown`. 8 | * 9 | * @author tangcent 10 | */ 11 | @ProvidedBy(MarkdownFormatterProvider::class) 12 | interface MarkdownFormatter { 13 | 14 | fun parseDocs(docs: List): String 15 | 16 | } 17 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/Emojis.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.postman 2 | 3 | import com.itangcent.utils.Emojis 4 | 5 | object Emojis { 6 | const val TEAM = Emojis.BUSTS 7 | const val PERSONAL = Emojis.BUST 8 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigProvider.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.postman 2 | 3 | import com.itangcent.condition.Exclusion 4 | import com.itangcent.idea.plugin.api.export.condition.ConditionOnChannel 5 | import com.itangcent.idea.plugin.api.export.core.EasyApiConfigProvider 6 | import com.itangcent.intellij.config.LocalFileSearchConfigProvider 7 | import com.itangcent.order.Order 8 | import com.itangcent.order.Ordered 9 | 10 | @ConditionOnChannel("postman") 11 | @Exclusion(EasyApiConfigProvider::class) 12 | @Order(Ordered.HIGHEST_PRECEDENCE) 13 | class PostmanConfigProvider : LocalFileSearchConfigProvider() { 14 | 15 | override fun configFileNames(): List { 16 | return listOf( 17 | ".postman.config", 18 | ".postman.yml", 19 | ".postman.yaml", 20 | 21 | ".easy.api.config", 22 | ".easy.api.yml", 23 | ".easy.api.yaml" 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanUrls.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.postman 2 | 3 | object PostmanUrls { 4 | 5 | const val INTEGRATIONS_DASHBOARD = "https://go.postman.co/integrations/services/pm_pro_api" 6 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/spring/SpringControllerAnnotationResolver.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.spring 2 | 3 | import com.google.inject.ProvidedBy 4 | import com.google.inject.Singleton 5 | import com.intellij.psi.PsiClass 6 | import com.itangcent.spi.SpiCompositeBeanProvider 7 | 8 | /* 9 | * This interface defines a contract for resolving whether a given PsiClass 10 | * has a Spring controller annotation. It is implemented by various classes 11 | * to provide different strategies for determining the presence of controller annotations. 12 | */ 13 | @ProvidedBy(SpringControllerAnnotationResolverCompositeProvider::class) 14 | interface SpringControllerAnnotationResolver { 15 | fun hasControllerAnnotation(psiClass: PsiClass): Boolean 16 | } 17 | 18 | @Singleton 19 | class SpringControllerAnnotationResolverCompositeProvider : 20 | SpiCompositeBeanProvider() -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/spring/SpringRequestMappingResolver.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.spring 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.intellij.psi.PsiElement 5 | 6 | /* 7 | * This interface defines a contract for resolving Spring request mapping annotations. 8 | * It is responsible for extracting mapping information from Spring MVC request mapping 9 | * annotations on classes and methods. This includes both standard Spring annotations 10 | * and custom annotations that may be used for request mapping. 11 | */ 12 | @ImplementedBy(DefaultSpringRequestMappingResolver::class) 13 | interface SpringRequestMappingResolver { 14 | 15 | /** 16 | * @param psiElement annotated element(PsiMethod/PsiClass) 17 | * @return annotation attributes 18 | */ 19 | fun resolveRequestMapping(psiElement: PsiElement): Map? 20 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/spring/StandardSpringControllerAnnotationResolver.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.spring 2 | 3 | import com.google.inject.Inject 4 | import com.intellij.psi.PsiClass 5 | import com.itangcent.intellij.jvm.AnnotationHelper 6 | 7 | /* 8 | * This class provides a standard implementation for resolving whether a given PsiClass 9 | * has a Spring controller annotation. 10 | */ 11 | class StandardSpringControllerAnnotationResolver : SpringControllerAnnotationResolver { 12 | 13 | @Inject 14 | private lateinit var annotationHelper: AnnotationHelper 15 | 16 | override fun hasControllerAnnotation(psiClass: PsiClass): Boolean { 17 | // Check for direct Spring controller annotations 18 | return SpringClassName.SPRING_CONTROLLER_ANNOTATION.any { annotationHelper.hasAnn(psiClass, it) } 19 | } 20 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/infer/MethodInferHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.infer 2 | 3 | import com.google.inject.ProvidedBy 4 | import com.intellij.psi.PsiMethod 5 | 6 | @ProvidedBy(MethodInferHelperProvider::class) 7 | interface MethodInferHelper { 8 | 9 | fun inferReturn(psiMethod: PsiMethod, option: Int = DefaultMethodInferHelper.DEFAULT_OPTION): Any? 10 | 11 | fun inferReturn( 12 | psiMethod: PsiMethod, 13 | caller: Any? = null, 14 | args: Array?, 15 | option: Int = DefaultMethodInferHelper.DEFAULT_OPTION 16 | ): Any? 17 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/infer/MethodInferHelperProvider.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.infer 2 | 3 | import com.google.inject.Inject 4 | import com.google.inject.Provider 5 | import com.google.inject.Singleton 6 | 7 | /** 8 | * Provider for MethodInferHelper that uses the factory to get the appropriate implementation 9 | */ 10 | @Singleton 11 | class MethodInferHelperProvider : Provider { 12 | 13 | @Inject 14 | private lateinit var methodInferHelperFactory: MethodInferHelperFactory 15 | 16 | override fun get(): MethodInferHelper { 17 | return methodInferHelperFactory.getMethodInferHelper() 18 | } 19 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/condition/ConditionOnSetting.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.condition 2 | 3 | import com.itangcent.idea.plugin.settings.Settings 4 | 5 | /** 6 | * Conditional that only matches when the special property in the [Settings] is true. 7 | * @param value properties 8 | */ 9 | @Target(AnnotationTarget.CLASS) 10 | @Retention(AnnotationRetention.RUNTIME) 11 | annotation class ConditionOnSetting(vararg val value: String, val havingValue: String = "") 12 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/condition/OnSettingCondition.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.condition 2 | 3 | import com.itangcent.common.utils.asBool 4 | import com.itangcent.common.utils.getPropertyValue 5 | import com.itangcent.condition.AnnotatedCondition 6 | import com.itangcent.idea.plugin.settings.SettingBinder 7 | import com.itangcent.intellij.context.ActionContext 8 | 9 | /** 10 | * Condition that checks for [ConditionOnSetting]. 11 | */ 12 | class OnSettingCondition : AnnotatedCondition() { 13 | 14 | override fun matches(actionContext: ActionContext, annotation: ConditionOnSetting): Boolean { 15 | val valueChecker = getValueChecker(annotation.havingValue) 16 | val settingBinder = actionContext.instance(SettingBinder::class) 17 | annotation.value.forEach { property -> 18 | if (!valueChecker(settingBinder.read().getPropertyValue(property))) { 19 | return false 20 | } 21 | } 22 | return true 23 | } 24 | 25 | private fun getValueChecker(havingValue: String): (Any?) -> Boolean { 26 | if (havingValue == "") { 27 | return { it.asBool() == true } 28 | } 29 | return { it?.toString() == havingValue } 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/AbstractEasyApiSettingGUI.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.configurable 2 | 3 | import com.itangcent.idea.plugin.settings.Settings 4 | 5 | abstract class AbstractEasyApiSettingGUI : EasyApiSettingGUI { 6 | 7 | protected var settingsInstance: Settings? = null 8 | 9 | override fun onCreate() { 10 | } 11 | 12 | override fun getSettings(): Settings { 13 | return (settingsInstance ?: Settings()).copy().also { readSettings((it)) } 14 | } 15 | 16 | override fun setSettings(settings: Settings) { 17 | this.settingsInstance = settings 18 | } 19 | 20 | override fun readSettings(settings: Settings) { 21 | } 22 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/EasyApiConfigurable.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.configurable 2 | 3 | import com.intellij.openapi.project.Project 4 | import com.itangcent.idea.plugin.dialog.EasyApiSettingGUI 5 | import com.itangcent.idea.plugin.settings.helper.MemoryPostmanSettingsHelper 6 | import com.itangcent.idea.plugin.settings.helper.PostmanSettingsHelper 7 | import com.itangcent.intellij.context.ActionContext 8 | import com.itangcent.intellij.context.ActionContextBuilder 9 | import com.itangcent.intellij.extend.guice.singleton 10 | import com.itangcent.intellij.extend.guice.with 11 | 12 | class EasyApiConfigurable(myProject: Project?) : AbstractEasyApiConfigurable(myProject) { 13 | 14 | override fun getId(): String { 15 | return "preference.EasyApiConfigurable" 16 | } 17 | 18 | override fun getDisplayName(): String { 19 | return "EasyApi" 20 | } 21 | 22 | override fun createGUI(): com.itangcent.idea.plugin.configurable.EasyApiSettingGUI { 23 | return EasyApiSettingGUI() 24 | } 25 | 26 | override fun afterBuildActionContext(builder: ActionContextBuilder) { 27 | super.afterBuildActionContext(builder) 28 | builder.bind(PostmanSettingsHelper::class) { it.with(MemoryPostmanSettingsHelper::class).singleton() } 29 | } 30 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/EasyApiOtherConfigurable.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.configurable 2 | 3 | import com.intellij.openapi.project.Project 4 | import com.itangcent.idea.plugin.dialog.EasyApiSettingOtherGUI 5 | 6 | class EasyApiOtherConfigurable(myProject: Project?) : AbstractEasyApiConfigurable(myProject) { 7 | 8 | override fun getId(): String { 9 | return "preference.EasyApiConfigurable.Other" 10 | } 11 | 12 | override fun getDisplayName(): String { 13 | return "Other" 14 | } 15 | 16 | override fun createGUI(): EasyApiSettingGUI { 17 | return EasyApiSettingOtherGUI() 18 | } 19 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/EasyApiRecommendConfigurable.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.configurable 2 | 3 | import com.intellij.openapi.project.Project 4 | import com.itangcent.idea.plugin.dialog.EasyApiSettingRecommendGUI 5 | 6 | class EasyApiRecommendConfigurable(myProject: Project?) : AbstractEasyApiConfigurable(myProject) { 7 | 8 | override fun getId(): String { 9 | return "preference.EasyApiConfigurable.Recommend" 10 | } 11 | 12 | override fun getDisplayName(): String { 13 | return "Recommend" 14 | } 15 | 16 | override fun createGUI(): EasyApiSettingGUI { 17 | return EasyApiSettingRecommendGUI() 18 | } 19 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/EasyApiSettingAIConfigurable.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.configurable 2 | 3 | import com.intellij.openapi.project.Project 4 | import com.itangcent.idea.plugin.dialog.EasyApiSettingAIGUI 5 | 6 | /** 7 | * Configurable for AI integration settings 8 | */ 9 | class EasyApiSettingAIConfigurable(myProject: Project?) : AbstractEasyApiConfigurable(myProject) { 10 | 11 | override fun getId(): String { 12 | return "preference.EasyApiConfigurable.AI" 13 | } 14 | 15 | override fun getDisplayName(): String { 16 | return "AI Integration" 17 | } 18 | 19 | override fun createGUI(): EasyApiSettingGUI { 20 | return EasyApiSettingAIGUI() 21 | } 22 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/EasyApiSettingBuiltInConfigConfigurable.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.configurable 2 | 3 | import com.intellij.openapi.project.Project 4 | import com.itangcent.idea.plugin.dialog.EasyApiSettingBuiltInConfigGUI 5 | 6 | class EasyApiSettingBuiltInConfigConfigurable(myProject: Project?) : AbstractEasyApiConfigurable(myProject) { 7 | 8 | override fun getId(): String { 9 | return "preference.EasyApiConfigurable.BuiltInConfig" 10 | } 11 | 12 | override fun getDisplayName(): String { 13 | return "BuiltInConfig" 14 | } 15 | 16 | override fun createGUI(): EasyApiSettingGUI { 17 | return EasyApiSettingBuiltInConfigGUI() 18 | } 19 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/EasyApiSettingGUI.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.configurable 2 | 3 | import com.itangcent.idea.plugin.settings.Settings 4 | import javax.swing.JComponent 5 | 6 | interface EasyApiSettingGUI { 7 | 8 | fun getRootPanel(): JComponent? 9 | 10 | fun onCreate() 11 | 12 | /** 13 | * get settings in UI 14 | */ 15 | fun getSettings(): Settings 16 | 17 | /** 18 | * set settings to UI 19 | */ 20 | fun setSettings(settings: Settings) 21 | 22 | /** 23 | * read settings from UI 24 | */ 25 | fun readSettings(settings: Settings) 26 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/EasyApiSettingBuiltInConfigGUI.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/TriggerSupport.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.dialog 2 | 3 | /** 4 | * @author tangcent 5 | */ 6 | class TriggerSupport { 7 | private var trigger: String? = null 8 | 9 | fun withTrigger(trigger: String, cancelIfTriggerNotMatch: Boolean = true, action: () -> Unit) { 10 | if (this.trigger != null && this.trigger != trigger) { 11 | if (cancelIfTriggerNotMatch) { 12 | return 13 | } 14 | action() 15 | return 16 | } 17 | this.trigger = trigger 18 | try { 19 | action() 20 | } finally { 21 | this.trigger = null 22 | } 23 | } 24 | 25 | fun getTrigger(): String? { 26 | return trigger 27 | } 28 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/format/MessageFormatter.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.format 2 | 3 | /** 4 | * Strategy interface that specifies a converter that can convert an object to a message that can be output. 5 | * 6 | * @author tangcent 7 | */ 8 | interface MessageFormatter { 9 | 10 | /** 11 | * Write an given object as a message. 12 | * 13 | * @param obj the object to write. 14 | * @param desc description of the object 15 | */ 16 | fun format(obj: Any?, desc: String? = null): String 17 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/format/SimpleJsonFormatter.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.format 2 | 3 | import com.google.inject.Singleton 4 | import com.itangcent.http.RequestUtils 5 | 6 | /** 7 | * Implementation of [com.itangcent.idea.plugin.format.MessageFormatter] 8 | * that can write the object as JSON string. 9 | * 10 | * @author tangcent 11 | */ 12 | @Singleton 13 | class SimpleJsonFormatter : MessageFormatter { 14 | override fun format(obj: Any?, desc: String?): String { 15 | return obj?.let { RequestUtils.parseRawBody(it) } ?: "" 16 | } 17 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/rule/GroovyRuleParser.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.rule 2 | 3 | /** 4 | * see @{link org.codehaus.groovy.jsr223.GroovyScriptEngineFactory} 5 | * 6 | */ 7 | class GroovyRuleParser : StandardJdkRuleParser() { 8 | override fun scriptType(): String { 9 | return "groovy" 10 | } 11 | 12 | } 13 | 14 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/rule/JsRuleParser.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.rule 2 | 3 | /** 4 | * see @{link jdk.nashorn.api.scripting.NashornScriptEngineFactory} 5 | * 6 | */ 7 | class JsRuleParser : StandardJdkRuleParser() { 8 | override fun scriptType(): String { 9 | return "JavaScript" 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/rule/RuleComputorKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.rule 2 | 3 | import com.itangcent.intellij.config.rule.RuleContext 4 | import com.itangcent.intellij.config.rule.RuleParser 5 | import com.itangcent.intellij.jvm.element.ExplicitElement 6 | 7 | 8 | fun RuleParser.contextOf(context: ExplicitElement<*>): RuleContext { 9 | return this.contextOf(context, context.psi()) 10 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/rule/UnsupportedScriptException.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.rule 2 | 3 | class UnsupportedScriptException : RuntimeException { 4 | 5 | private val type: String 6 | 7 | constructor(type: String) : super("$type was unsupported") { 8 | this.type = type 9 | } 10 | 11 | fun getType(): String { 12 | return type 13 | } 14 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/DefaultSettingBinder.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings 2 | 3 | import com.google.inject.Inject 4 | import com.google.inject.Singleton 5 | 6 | @Singleton 7 | class DefaultSettingBinder : SettingBinder { 8 | 9 | @Inject 10 | private lateinit var xmlSettingBinder: XmlSettingBinder 11 | 12 | private val cachedSettingBinder by lazy { 13 | xmlSettingBinder.lazy() 14 | } 15 | 16 | override fun read(): Settings { 17 | return cachedSettingBinder.read() 18 | } 19 | 20 | override fun save(t: Settings?) { 21 | xmlSettingBinder.save(t) 22 | cachedSettingBinder.save(t) 23 | } 24 | 25 | override fun tryRead(): Settings? { 26 | return cachedSettingBinder.tryRead() 27 | } 28 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/HttpClientType.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings 2 | 3 | /** 4 | * @author tangcent 5 | * @date 2024/04/28 6 | */ 7 | enum class HttpClientType( 8 | val value: String 9 | ) { 10 | APACHE("Apache"), 11 | OKHTTP("Okhttp"); 12 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/MarkdownFormatType.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings 2 | 3 | enum class MarkdownFormatType(var desc: String) { 4 | SIMPLE("simple columns, include name、type、desc"), 5 | ULTIMATE("more columns than simple, include name、type、required、default、desc") 6 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/PostmanExportMode.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings 2 | 3 | 4 | /** 5 | * Used to indicate whether to create new collection or update existed collection when 6 | * export api to postman. 7 | * 8 | * @author tangcent 9 | */ 10 | enum class PostmanExportMode(var desc: String) { 11 | COPY("always create new collection"), 12 | UPDATE("try update existed collection") 13 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/PostmanJson5FormatType.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings 2 | 3 | /** 4 | * types: 5 | * api-request: 1 6 | * api-response: X 7 | * example-request: 4 8 | * example-response: 8 9 | */ 10 | enum class PostmanJson5FormatType(val desc: String, private val types: Int) { 11 | NONE("not use json5 anywhere", 0), 12 | REQUEST_ONLY("for request only", 1 or 4), 13 | RESPONSE_ONLY("for response only", 8), 14 | EXAMPLE_ONLY("for example only", 4 or 8), 15 | ALL("always use json5", 1 or 4 or 8); 16 | 17 | fun needUseJson5(type: Int): Boolean { 18 | return (this.types and type) != 0 19 | } 20 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/SettingBinder.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.itangcent.intellij.file.BeanBinder 5 | import com.itangcent.intellij.file.CachedBeanBinder 6 | 7 | @ImplementedBy(DefaultSettingBinder::class) 8 | interface SettingBinder : BeanBinder 9 | 10 | fun SettingBinder.update(updater: Settings.() -> Unit) { 11 | this.read().also(updater).let { this.save(it) } 12 | } 13 | 14 | fun SettingBinder.lazy(): SettingBinder { 15 | return CachedSettingBinder(this) 16 | } 17 | 18 | class CachedSettingBinder(settingBinder: SettingBinder) : CachedBeanBinder(settingBinder), SettingBinder { 19 | 20 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/helper/BuiltInConfigSettingsHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings.helper 2 | 3 | import com.google.inject.Inject 4 | import com.google.inject.Singleton 5 | import com.itangcent.idea.plugin.settings.SettingBinder 6 | 7 | @Singleton 8 | class BuiltInConfigSettingsHelper { 9 | 10 | @Inject 11 | private lateinit var settingBinder: SettingBinder 12 | 13 | fun builtInConfig(): String? { 14 | return settingBinder.read().builtInConfig 15 | } 16 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/helper/MarkdownSettingsHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings.helper 2 | 3 | import com.google.inject.Inject 4 | import com.google.inject.Singleton 5 | import com.itangcent.idea.plugin.settings.MarkdownFormatType 6 | import com.itangcent.idea.plugin.settings.SettingBinder 7 | import com.itangcent.idea.utils.Charsets 8 | import java.nio.charset.Charset 9 | 10 | @Singleton 11 | class MarkdownSettingsHelper { 12 | 13 | @Inject 14 | private lateinit var settingBinder: SettingBinder 15 | 16 | fun outputCharset(): Charset { 17 | return Charsets.forName(settingBinder.read().outputCharset)?.charset() ?: kotlin.text.Charsets.UTF_8 18 | } 19 | 20 | fun outputDemo(): Boolean { 21 | return settingBinder.read().outputDemo 22 | } 23 | 24 | fun markdownFormatType(): MarkdownFormatType { 25 | return MarkdownFormatType.valueOf(settingBinder.read().markdownFormatType) 26 | } 27 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/helper/MemoryPostmanSettingsHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings.helper 2 | 3 | import com.google.inject.Singleton 4 | import com.itangcent.intellij.context.AutoClear 5 | 6 | @Singleton 7 | class MemoryPostmanSettingsHelper : DefaultPostmanSettingsHelper() { 8 | 9 | @AutoClear 10 | private var privateToken: String? = null 11 | 12 | override fun getPrivateToken(dumb: Boolean): String? { 13 | if (privateToken != null) { 14 | return privateToken 15 | } 16 | return super.getPrivateToken(dumb) 17 | } 18 | 19 | fun setPrivateToken(privateToken: String?) { 20 | this.privateToken = privateToken 21 | } 22 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/helper/PostmanSettingsHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings.helper 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.itangcent.idea.plugin.settings.PostmanExportMode 5 | import com.itangcent.idea.plugin.settings.PostmanJson5FormatType 6 | 7 | @ImplementedBy(DefaultPostmanSettingsHelper::class) 8 | interface PostmanSettingsHelper { 9 | 10 | fun hasPrivateToken(): Boolean 11 | 12 | fun getPrivateToken(dumb: Boolean = true): String? 13 | 14 | fun getWorkspace(dumb: Boolean = true): String? 15 | 16 | fun wrapCollection(): Boolean 17 | 18 | fun autoMergeScript(): Boolean 19 | 20 | fun buildExample(): Boolean 21 | 22 | fun postmanJson5FormatType(): PostmanJson5FormatType 23 | 24 | fun postmanExportMode(): PostmanExportMode 25 | 26 | fun getCollectionId(module: String, dumb: Boolean = true): String? 27 | 28 | fun addCollectionId(module: String, collectionId: String) 29 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/helper/SupportSettingsHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings.helper 2 | 3 | import com.google.inject.Inject 4 | import com.google.inject.Singleton 5 | import com.itangcent.idea.plugin.settings.SettingBinder 6 | 7 | @Singleton 8 | @Deprecated("use @ConditionOnSetting") 9 | class SupportSettingsHelper { 10 | 11 | @Inject 12 | private lateinit var settingBinder: SettingBinder 13 | 14 | fun methodDocEnable(): Boolean { 15 | return settingBinder.read().methodDocEnable 16 | } 17 | 18 | fun genericEnable(): Boolean { 19 | return settingBinder.read().genericEnable 20 | } 21 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/xml/ApplicationSettingsComponent.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings.xml 2 | 3 | import com.intellij.openapi.components.PersistentStateComponent 4 | import com.intellij.openapi.components.RoamingType 5 | import com.intellij.openapi.components.State 6 | import com.intellij.openapi.components.Storage 7 | 8 | @State( 9 | name = "EasyApiSetting", 10 | storages = [Storage(value = "EasyApiSetting.xml", roamingType = RoamingType.DISABLED)] 11 | ) 12 | class ApplicationSettingsComponent : PersistentStateComponent { 13 | 14 | private var applicationSettings: ApplicationSettings? = null 15 | 16 | override fun getState(): ApplicationSettings? { 17 | return applicationSettings?.copy() 18 | } 19 | 20 | override fun loadState(state: ApplicationSettings) { 21 | this.applicationSettings = state 22 | } 23 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/xml/ProjectSettingsComponent.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings.xml 2 | 3 | import com.intellij.openapi.components.PersistentStateComponent 4 | import com.intellij.openapi.components.State 5 | import com.intellij.openapi.components.Storage 6 | 7 | @State( 8 | name = "EasyApiProjectSetting", 9 | storages = [Storage("EasyApiProjectSetting.xml")] 10 | ) 11 | class ProjectSettingsComponent : PersistentStateComponent { 12 | 13 | private var projectSettings: ProjectSettings? = null 14 | 15 | override fun getState(): ProjectSettings? { 16 | return projectSettings?.copy() 17 | } 18 | 19 | override fun loadState(state: ProjectSettings) { 20 | this.projectSettings = state 21 | } 22 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/support/IdeaSupport.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.support 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.google.inject.Singleton 5 | import com.intellij.ide.browsers.BrowserLauncher 6 | import com.intellij.openapi.application.ApplicationManager 7 | 8 | @ImplementedBy(DefaultIdeaSupport::class) 9 | interface IdeaSupport { 10 | fun openUrl(url: String) 11 | } 12 | 13 | @Singleton 14 | class DefaultIdeaSupport : IdeaSupport { 15 | override fun openUrl(url: String) { 16 | ApplicationManager.getApplication() 17 | .getService(BrowserLauncher::class.java) 18 | .open(url) 19 | } 20 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/ui/UI.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.ui 2 | 3 | import com.itangcent.idea.utils.SwingUtils 4 | import com.itangcent.intellij.util.UIUtils 5 | import java.awt.Dialog 6 | 7 | interface UI { 8 | 9 | fun focusUI() { 10 | (this as? Dialog)?.let { SwingUtils.focus(it) } 11 | } 12 | 13 | fun showUI() { 14 | (this as? Dialog)?.let { UIUtils.show(it) } 15 | } 16 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/utils/SessionStorage.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.utils 2 | 3 | import com.google.inject.Singleton 4 | import com.itangcent.annotation.script.ScriptTypeName 5 | import com.itangcent.common.utils.sub 6 | import com.itangcent.idea.plugin.utils.Storage.Companion.DEFAULT_GROUP 7 | 8 | /** 9 | * Implementation of [Storage] based on memory 10 | * The [SessionStorage] can only be accessed in the current action. 11 | */ 12 | @Singleton 13 | @ScriptTypeName("session") 14 | class SessionStorage : AbstractStorage() { 15 | 16 | private val data: MutableMap by lazy { linkedMapOf() } 17 | 18 | override fun getCache(group: String): MutableMap { 19 | return data.sub(group) 20 | } 21 | 22 | override fun onUpdate(group: String?, cache: MutableMap) { 23 | if (cache.isEmpty()) { 24 | data.remove(group ?: DEFAULT_GROUP) 25 | } else { 26 | data[group ?: DEFAULT_GROUP] = cache 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/psi/PsiClassFinder.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.psi 2 | 3 | import com.intellij.openapi.project.Project 4 | import com.intellij.psi.JavaPsiFacade 5 | import com.intellij.psi.PsiClass 6 | import com.intellij.psi.search.GlobalSearchScope 7 | import com.itangcent.intellij.context.ActionContext 8 | 9 | object PsiClassFinder { 10 | 11 | fun findClass(fqClassName: String, project: Project): PsiClass? { 12 | return JavaPsiFacade.getInstance(project).findClass(fqClassName, GlobalSearchScope.allScope(project)) 13 | } 14 | 15 | fun findClass(fqClassName: String): PsiClass? { 16 | val project = ActionContext.getContext()?.instance(Project::class) ?: return null 17 | return findClass(fqClassName, project) 18 | } 19 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/psi/PsiClassResource.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.psi 2 | 3 | import com.intellij.psi.PsiClass 4 | import com.intellij.psi.PsiElement 5 | 6 | class PsiClassResource : PsiResource { 7 | 8 | private val psiClass: PsiClass 9 | 10 | constructor(psiClass: PsiClass) { 11 | this.psiClass = psiClass 12 | } 13 | 14 | override fun resourceClass(): PsiClass { 15 | return psiClass 16 | } 17 | 18 | override fun resource(): PsiElement { 19 | return psiClass 20 | } 21 | 22 | override fun equals(other: Any?): Boolean { 23 | if (this === other) return true 24 | if (javaClass != other?.javaClass) return false 25 | 26 | other as PsiClassResource 27 | 28 | if (psiClass != other.psiClass) return false 29 | 30 | return true 31 | } 32 | 33 | override fun hashCode(): Int { 34 | return psiClass.hashCode() 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/psi/PsiMethodResource.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.psi 2 | 3 | import com.intellij.psi.PsiClass 4 | import com.intellij.psi.PsiElement 5 | import com.intellij.psi.PsiMethod 6 | 7 | class PsiMethodResource : PsiResource { 8 | 9 | private val psiMethod: PsiMethod 10 | private val psiClass: PsiClass 11 | 12 | constructor(psiMethod: PsiMethod, psiClass: PsiClass) { 13 | this.psiMethod = psiMethod 14 | this.psiClass = psiClass 15 | } 16 | 17 | override fun resourceClass(): PsiClass { 18 | return psiClass 19 | } 20 | 21 | override fun resource(): PsiElement { 22 | return psiMethod 23 | } 24 | 25 | override fun equals(other: Any?): Boolean { 26 | if (this === other) return true 27 | if (javaClass != other?.javaClass) return false 28 | 29 | other as PsiMethodResource 30 | 31 | if (psiMethod != other.psiMethod) return false 32 | if (psiClass != other.psiClass) return false 33 | 34 | return true 35 | } 36 | 37 | override fun hashCode(): Int { 38 | var result = psiMethod.hashCode() 39 | result = 31 * result + psiClass.hashCode() 40 | return result 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/psi/PsiMethodSet.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.psi 2 | 3 | import com.intellij.psi.PsiMethod 4 | import com.itangcent.intellij.context.ActionContext 5 | 6 | class PsiMethodSet { 7 | 8 | private val parsedMethods = HashSet() 9 | private val parsedMethodNames = HashSet() 10 | 11 | fun add(method: PsiMethod): Boolean { 12 | val methodName = ActionContext.getContext()!!.callInReadUI { method.name }!! 13 | if (parsedMethodNames.add(methodName)) { 14 | parsedMethods.add(method) 15 | return true 16 | } 17 | if (parsedMethods.contains(method)) { 18 | return false 19 | } 20 | for (psiMethod in parsedMethods) { 21 | if (PsiMethodUtil.isSuperMethod(psiMethod, method) 22 | || PsiMethodUtil.isSuperMethod(psiMethod, method) 23 | ) { 24 | return false 25 | } 26 | } 27 | parsedMethods.add(method) 28 | return true 29 | } 30 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/psi/PsiMethodUtil.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.psi 2 | 3 | import com.intellij.psi.PsiMethod 4 | import com.intellij.psi.util.PsiSuperMethodUtil 5 | import org.jetbrains.annotations.NotNull 6 | 7 | object PsiMethodUtil { 8 | fun isSuperMethod(@NotNull method: PsiMethod, @NotNull superMethod: PsiMethod): Boolean { 9 | if (method.name != superMethod.name) { 10 | return false 11 | } 12 | if (method.parameters.size != superMethod.parameters.size) { 13 | return false 14 | } 15 | return PsiSuperMethodUtil.isSuperMethod(method, superMethod) 16 | } 17 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/psi/PsiResource.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.psi 2 | 3 | import com.intellij.psi.PsiClass 4 | import com.intellij.psi.PsiElement 5 | import com.intellij.psi.PsiMethod 6 | import com.itangcent.common.model.Doc 7 | 8 | interface PsiResource { 9 | 10 | fun resourceClass(): PsiClass? 11 | 12 | fun resource(): PsiElement? 13 | 14 | } 15 | 16 | fun Doc?.resourceClass(): PsiClass? { 17 | if (this?.resource == null) return null 18 | return when (val res = this.resource) { 19 | is PsiResource -> res.resourceClass() 20 | is PsiClass -> res 21 | is PsiMethod -> res.containingClass 22 | else -> null 23 | } 24 | } 25 | 26 | fun Doc?.resource(): PsiElement? { 27 | if (this?.resource == null) return null 28 | return when (val res = this.resource) { 29 | is PsiResource -> res.resource() 30 | is PsiElement -> res 31 | else -> null 32 | } 33 | } 34 | 35 | fun Doc?.resourceMethod(): PsiMethod? { 36 | return when (val res = this.resource()) { 37 | is PsiMethod -> res 38 | else -> null 39 | } 40 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/swing/ActiveWindowProvider.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.swing 2 | 3 | import java.awt.Component 4 | 5 | interface ActiveWindowProvider { 6 | fun activeWindow(): Component? 7 | } 8 | 9 | interface MutableActiveWindowProvider : ActiveWindowProvider { 10 | fun setActiveWindow(activeWindow: Component?) 11 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/swing/IconCustomized.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.swing 2 | 3 | import javax.swing.Icon 4 | 5 | /** 6 | * Defines the icon this component will display. 7 | * If the value of icon is null, the default icon for the current scenario will be used 8 | */ 9 | interface IconCustomized { 10 | 11 | /** 12 | * Returns the graphic image (glyph, icon) that the label displays. 13 | */ 14 | fun icon(): Icon? 15 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/swing/SimpleActiveWindowProvider.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.swing 2 | 3 | import com.google.inject.Singleton 4 | import java.awt.Component 5 | 6 | @Singleton 7 | class SimpleActiveWindowProvider : MutableActiveWindowProvider { 8 | 9 | private var activeWindow: Component? = null 10 | 11 | override fun setActiveWindow(activeWindow: Component?) { 12 | this.activeWindow = activeWindow 13 | } 14 | 15 | override fun activeWindow(): Component? { 16 | return this.activeWindow 17 | } 18 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/swing/ToolTipAble.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.swing 2 | 3 | /** 4 | * A component which has the text to display in a tool tip. 5 | */ 6 | interface ToolTipAble { 7 | 8 | /** 9 | * The text to display in a tool tip. 10 | * The text displays when the cursor lingers over the component. 11 | * If the text is [null],the tool tip is turned off for this component 12 | */ 13 | fun toolTip(): String? 14 | } 15 | 16 | /** 17 | * For compatible only. 18 | */ 19 | typealias Tooltipable = ToolTipAble -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/utils/DigestUtils.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.utils 2 | 3 | import java.security.MessageDigest 4 | import kotlin.text.Charsets 5 | 6 | /** 7 | * Utility functions for message digest operations 8 | */ 9 | object DigestUtils { 10 | 11 | /** 12 | * Calculates the MD5 hash of the given string 13 | * 14 | * @param input The string to hash 15 | * @return The MD5 hash as a hexadecimal string 16 | */ 17 | fun md5(input: String): String { 18 | return md5(input.toByteArray(Charsets.UTF_8)) 19 | } 20 | 21 | /** 22 | * Calculates the MD5 hash of the given byte array 23 | * 24 | * @param input The byte array to hash 25 | * @return The MD5 hash as a hexadecimal string 26 | */ 27 | fun md5(input: ByteArray): String { 28 | val md = MessageDigest.getInstance("MD5") 29 | val digest = md.digest(input) 30 | return digest.joinToString("") { "%02x".format(it) } 31 | } 32 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/utils/FileSelectHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.utils 2 | 3 | import com.google.inject.ImplementedBy 4 | import java.io.File 5 | 6 | @ImplementedBy(DefaultFileSelectHelper::class) 7 | interface FileSelectHelper { 8 | 9 | fun selectFile(onSelect: (File?) -> Unit) 10 | 11 | fun selectFile(onSelect: (File) -> Unit, 12 | onCancel: () -> Unit) 13 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/utils/GsonExUtils.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.utils 2 | 3 | object GsonExUtils { 4 | fun resolveGsonLazily(str: String): String { 5 | if (str.contains("\"com.google.gson.internal.LazilyParsedNumber\"")) { 6 | return str.replace("\"com.google.gson.internal.LazilyParsedNumber\"", "\"java.lang.Integer\"") 7 | } 8 | return str 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/utils/ModuleHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.utils 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.intellij.openapi.module.Module 5 | import com.intellij.psi.PsiClass 6 | import com.intellij.psi.PsiFile 7 | import com.intellij.psi.PsiMethod 8 | 9 | /** 10 | * find [Module] name 11 | */ 12 | @ImplementedBy(DefaultModuleHelper::class) 13 | interface ModuleHelper { 14 | 15 | fun findModule(resource: Any): String? 16 | 17 | fun findModule(psiMethod: PsiMethod): String? 18 | 19 | fun findModule(cls: PsiClass): String? 20 | 21 | fun findModule(psiFile: PsiFile): String? 22 | 23 | fun findModuleByPath(path: String?): String? 24 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/idea/utils/SystemProvider.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.utils 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.google.inject.Singleton 5 | 6 | @ImplementedBy(DefaultSystemProvider::class) 7 | interface SystemProvider { 8 | fun currentTimeMillis(): Long 9 | 10 | fun runtime(): Runtime 11 | } 12 | 13 | @Singleton 14 | class DefaultSystemProvider : SystemProvider { 15 | override fun currentTimeMillis(): Long { 16 | return System.currentTimeMillis() 17 | } 18 | 19 | override fun runtime(): Runtime { 20 | return Runtime.getRuntime(); 21 | } 22 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/intellij/context/AutoClear.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.intellij.context 2 | 3 | /** 4 | * Annotation to mark properties that should be automatically cleared 5 | * after each action is completed (when ACTION_COMPLETED event is fired). 6 | * 7 | * Usage: 8 | * ```kotlin 9 | * @AutoClear 10 | * private var tempData: String? = null 11 | * ``` 12 | */ 13 | @Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) 14 | @Retention(AnnotationRetention.RUNTIME) 15 | annotation class AutoClear -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/intellij/extend/ThrottleKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.intellij.extend 2 | 3 | import com.itangcent.intellij.extend.rx.Throttle 4 | 5 | fun Throttle.acquireGreedy(cd: Long) { 6 | while (true) { 7 | if (this.acquire(cd)) { 8 | return 9 | } 10 | Thread.sleep(cd / 4) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/intellij/util/CacheAble.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.intellij.util 2 | 3 | import com.google.inject.ImplementedBy 4 | 5 | @ImplementedBy(DefaultCacheAle::class) 6 | interface CacheAble { 7 | 8 | fun cache(key: Any, action: () -> T?): T? 9 | 10 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/intellij/util/DefaultCacheAle.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.intellij.util 2 | 3 | import com.google.inject.Singleton 4 | import com.itangcent.common.utils.safeComputeIfAbsent 5 | 6 | @Singleton 7 | class DefaultCacheAle : CacheAble { 8 | 9 | val cache: MutableMap = HashMap() 10 | 11 | @Suppress("UNCHECKED_CAST") 12 | override fun cache(key: Any, action: () -> T?): T? { 13 | val value = cache.safeComputeIfAbsent(key) { 14 | action() ?: NULL 15 | } 16 | if (value == NULL) { 17 | return null 18 | } 19 | return value as T? 20 | } 21 | 22 | companion object { 23 | val NULL = Any() 24 | } 25 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/intellij/util/FileType.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.intellij.util 2 | 3 | import com.itangcent.intellij.context.ActionContext 4 | import com.itangcent.intellij.tip.OnlyOnceInContextTip 5 | import com.itangcent.intellij.tip.TipsHelper 6 | 7 | /** 8 | * All file types currently supported. 9 | */ 10 | enum class FileType(private val suffix: String) { 11 | 12 | JAVA("java"), 13 | KOTLIN("kt"), 14 | GROOVY("groovy") 15 | //, SCALA("scala") 16 | ; 17 | 18 | fun suffix(): String { 19 | return suffix 20 | } 21 | 22 | companion object { 23 | private val SUPPORT_SUPPORT_TIP = OnlyOnceInContextTip( 24 | "For support scala," + 25 | " please download plugin from https://github.com/tangcent/easy-api/releases" 26 | ) 27 | 28 | fun acceptable(fileName: String): Boolean { 29 | if (fileName.endsWith("scala")) { 30 | ActionContext.getContext()?.instance(TipsHelper::class)?.showTips(SUPPORT_SUPPORT_TIP) 31 | } 32 | return values().any { fileName.endsWith(it.suffix()) } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/logger/ConfigurableLogger.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.logger 2 | 3 | import com.itangcent.annotation.script.ScriptIgnore 4 | import com.itangcent.annotation.script.ScriptTypeName 5 | import com.itangcent.intellij.logger.Level 6 | import com.itangcent.intellij.logger.Logger 7 | 8 | @ScriptIgnore("processLog", "log") 9 | @ScriptTypeName("logger") 10 | class ConfigurableLogger( 11 | private val delegateLogger: Logger, 12 | private val loggerLevel: Int 13 | ) : Logger { 14 | 15 | override fun log(level: Level, msg: String) { 16 | if (level.level <= loggerLevel) { 17 | return 18 | } 19 | delegateLogger.log(level, msg) 20 | } 21 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/order/Order.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.order 2 | 3 | /** 4 | * [Order] defines the sort order for an annotated component. 5 | * The value is optional and represents an order value as defined in the Ordered interface. 6 | * Lower values have higher priority. The default value is [Ordered.DEFAULT_PRECEDENCE], 7 | * indicating normal priority. 8 | */ 9 | @Target(AnnotationTarget.CLASS) 10 | @Retention(AnnotationRetention.RUNTIME) 11 | annotation class Order(val order: Int = Ordered.DEFAULT_PRECEDENCE) 12 | -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/order/Ordered.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.order 2 | 3 | import kotlin.reflect.full.findAnnotation 4 | 5 | /** 6 | * Objects that implement this interface can be sorted according to their order value. 7 | * The order value is typically an integer that represents the relative order of the 8 | * object in a sequence or collection. 9 | */ 10 | interface Ordered { 11 | /** 12 | * Returns the order value of this object. 13 | */ 14 | fun order(): Int 15 | 16 | companion object { 17 | /** 18 | * The highest possible order value. 19 | */ 20 | const val HIGHEST_PRECEDENCE = Int.MIN_VALUE 21 | 22 | /** 23 | * The lowest possible order value. 24 | */ 25 | const val LOWEST_PRECEDENCE = Int.MAX_VALUE 26 | 27 | /** 28 | * The default order value. 29 | */ 30 | const val DEFAULT_PRECEDENCE = 0 31 | } 32 | } 33 | 34 | fun Any.order(): Int { 35 | //implement of [Ordered] 36 | if (this is Ordered) { 37 | return this.order() 38 | } 39 | 40 | //annotated with [Order] 41 | this::class.findAnnotation()?.let { return it.order } 42 | 43 | return 0 44 | 45 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/spi/SpiSingleBeanProvider.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.spi 2 | 3 | import com.itangcent.intellij.context.ActionContext 4 | import kotlin.reflect.KClass 5 | 6 | /** 7 | * A provider that loads the first available implementation of a service type. 8 | */ 9 | abstract class SpiSingleBeanProvider : AbstractSpiBeanProvider() { 10 | 11 | override fun loadBean(actionContext: ActionContext, kClass: KClass): T { 12 | val services = SpiCompositeLoader.load(actionContext, kClass) 13 | if (services.isEmpty()) { 14 | throw IllegalStateException("No services found for ${kClass.qualifiedName}") 15 | } 16 | return services.first() as T 17 | } 18 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/suv/http/AbstractHttpClientProvider.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.suv.http 2 | 3 | import com.itangcent.http.HttpClient 4 | 5 | /** 6 | * Abstract base class for creating and providing an HttpClient instance. 7 | * This class implements the HttpClientProvider interface and uses a singleton pattern to 8 | * ensure that a single, shared instance of HttpClient is provided across the entire application. 9 | */ 10 | abstract class AbstractHttpClientProvider : HttpClientProvider { 11 | 12 | /** 13 | * The HttpClient instance that will be provided by this provider. 14 | * This instance is created lazily and is shared across the entire application. 15 | */ 16 | protected val httpClientInstance: HttpClient by lazy { 17 | buildHttpClient() 18 | } 19 | 20 | /** 21 | * Retrieve the shared instance of HttpClient. 22 | */ 23 | override fun getHttpClient(): HttpClient = httpClientInstance 24 | 25 | /** 26 | * Create and configure an instance of HttpClient. 27 | */ 28 | abstract fun buildHttpClient(): HttpClient 29 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/suv/http/HttpClientProvider.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.suv.http 2 | 3 | import com.google.inject.ImplementedBy 4 | import com.google.inject.ProvidedBy 5 | import com.google.inject.Singleton 6 | import com.itangcent.http.HttpClient 7 | import com.itangcent.spi.SpiSingleBeanProvider 8 | 9 | 10 | /** 11 | * Defines an interface for obtaining an instance of HttpClient. 12 | * 13 | * It is the responsibility of each implementation to determine whether to return 14 | * the same instance of HttpClient consistently or to create a new instance for each request. 15 | * 16 | * @author tangcent 17 | * @date 2024/05/08 18 | */ 19 | @ProvidedBy(HttpClientProviderProvider::class) 20 | interface HttpClientProvider { 21 | 22 | /** 23 | * Retrieve an instance of HttpClient, either as a singleton or as a new instance per call. 24 | */ 25 | fun getHttpClient(): HttpClient 26 | } 27 | 28 | @Singleton 29 | class HttpClientProviderProvider : SpiSingleBeanProvider() -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/utils/Action.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | import java.util.concurrent.atomic.AtomicBoolean 4 | 5 | fun Function0.disposable(): Function0 { 6 | if (this is DisposableFunction0) { 7 | return this 8 | } 9 | return DisposableFunction0(this) 10 | } 11 | 12 | @Suppress("UNCHECKED_CAST") 13 | fun Function0<*>.asUnit(): Function0 { 14 | return this as Function0 15 | } 16 | 17 | fun Function1.disposable(): Function1 { 18 | if (this is DisposableFunction1) { 19 | return this 20 | } 21 | return DisposableFunction1(this) 22 | } 23 | 24 | class DisposableFunction0(val function: Function0) : Function0 { 25 | private var todo = AtomicBoolean(true) 26 | 27 | override fun invoke(): T? { 28 | if (todo.compareAndSet(true, false)) { 29 | return function() 30 | } 31 | return null 32 | } 33 | } 34 | 35 | class DisposableFunction1(val function: Function1) : Function1 { 36 | private var todo = AtomicBoolean(true) 37 | 38 | override fun invoke(p1: P): R? { 39 | if (todo.compareAndSet(true, false)) { 40 | return function(p1) 41 | } 42 | return null 43 | } 44 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/utils/Emojis.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | object Emojis { 4 | 5 | const val BUST = "\uD83D\uDC64" 6 | 7 | const val BUSTS = "\uD83D\uDC65" 8 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/utils/EnumKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | object EnumKit { 4 | /** 5 | * Safely converts a string to an enum constant, returning null if the name doesn't match any enum value 6 | * instead of throwing an IllegalArgumentException. 7 | * 8 | * @param name The name of the enum constant to return 9 | * @return The enum constant of the specified name, or null if not found 10 | */ 11 | inline fun > safeValueOf(name: String?): T? { 12 | if (name == null) return null 13 | return try { 14 | java.lang.Enum.valueOf(T::class.java, name) 15 | } catch (_: IllegalArgumentException) { 16 | null 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/utils/FileKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | import java.io.File 4 | 5 | /** 6 | * Returns a path string with `/` converted to the OS-specific separator character. 7 | * On OSes where the separator is already `/`, the original string is returned. 8 | */ 9 | fun String.localPath(): String { 10 | if (File.separatorChar != '/') { 11 | return this.replace('/', File.separatorChar) 12 | } 13 | return this 14 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/utils/GiteeSupport.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | import java.util.regex.Pattern 4 | 5 | /** 6 | * Converts a raw GitHub URL to a Gitee raw URL. 7 | * 8 | * Raw URLs have the format: 9 | * `https://raw.githubusercontent.com/$user/$project/$file` 10 | * 11 | * This converts it to the Gitee raw URL format: 12 | * `https://gitee.com/$user/$project/raw/$file` 13 | * 14 | * @author tangcent 15 | */ 16 | object GiteeSupport { 17 | 18 | private val GITHUB_RAW_URL_REGEX = 19 | Pattern.compile("https://raw.githubusercontent.com/(.*?)/(.*?)/(.*?)") 20 | 21 | /** 22 | * Converts a raw GitHub URL to a Gitee raw URL. 23 | * 24 | * https://raw.githubusercontent.com/$user/$project/$path 25 | * -> 26 | * https://gitee.com/$user/$project/raw/$path 27 | */ 28 | fun convertUrlFromGithub(githubUrl: String): String? { 29 | val matcher = GITHUB_RAW_URL_REGEX.matcher(githubUrl) 30 | 31 | if (!matcher.matches()) return null 32 | 33 | val giteeUser = matcher.group(1) 34 | val giteeProject = matcher.group(2) 35 | val giteeFilePath = matcher.group(3) 36 | return "https://gitee.com/$giteeUser/$giteeProject/raw/$giteeFilePath" 37 | } 38 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/utils/Initializable.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | import com.itangcent.intellij.context.ActionContext 4 | 5 | /** 6 | * Interface to be implemented by beans that need to react once all their properties 7 | * have been injected by [ActionContext]: e.g. to perform custom initialization, 8 | * or merely to check that all mandatory properties have been set. 9 | */ 10 | interface Initializable { 11 | 12 | fun init() 13 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/utils/NonReentrant.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | object NonReentrant { 4 | 5 | private val flagThreadLocal = ThreadLocal.withInitial { mutableSetOf() } 6 | 7 | fun call(flag: String, action: () -> T): T { 8 | val flags = flagThreadLocal.get() 9 | if (flags.contains(flag)) { 10 | throw NonReentrantException(flag) 11 | } 12 | flags.add(flag) 13 | try { 14 | return action() 15 | } finally { 16 | flags.remove(flag) 17 | } 18 | } 19 | } 20 | 21 | class NonReentrantException(val flag: String) : Exception("should not reentrant calls [$flag]") -------------------------------------------------------------------------------- /idea-plugin/src/main/kotlin/com/itangcent/utils/StringKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | /** 4 | * A map of escape characters to their unescaped versions. 5 | */ 6 | private val escapeCharacters = mapOf( 7 | 'b' to '\b', // Backspace 8 | 't' to '\t', // Tab 9 | 'n' to '\n', // Newline 10 | 'r' to '\r', // Carriage return 11 | '\\' to '\\', // Backslash 12 | ) 13 | 14 | /** 15 | * Used to convert escaped characters in a string to their unescaped version. 16 | * For example, "\\n" would be converted to "\n". 17 | * 18 | * @return The unescaped string. 19 | */ 20 | fun String.unescape(): String { 21 | val sb = StringBuilder() 22 | var escaped = false 23 | for (ch in this) { 24 | if (!escaped) { 25 | if (ch == '\\') { 26 | escaped = true 27 | } else { 28 | sb.append(ch) 29 | } 30 | continue 31 | } 32 | 33 | escaped = false 34 | if (escapeCharacters.containsKey(ch)) { 35 | sb.append(escapeCharacters[ch]) 36 | continue 37 | } 38 | 39 | sb.append('\\') 40 | sb.append(ch) 41 | continue 42 | } 43 | if (escaped) { 44 | sb.append('\\') 45 | } 46 | return sb.toString() 47 | } -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/.default.built.in.easy.api.config: -------------------------------------------------------------------------------- 1 | #configs 2 | #dev=false 3 | #auto.format.url=true 4 | #max.deep=10 5 | #max.elements=512 -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/.default.remote.easy.api.config: -------------------------------------------------------------------------------- 1 | !https://raw.githubusercontent.com/tangcent/easy-api/master/third/javax.validation.mock.config 2 | !https://raw.githubusercontent.com/tangcent/easy-api/master/third/swagger3.config 3 | !https://raw.githubusercontent.com/tangcent/easy-api/master/third/swagger.config 4 | !https://raw.githubusercontent.com/tangcent/easy-api/master/third/swagger.advanced.config 5 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/easy-api-kotlin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/easy-api-scala.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.ai.AIService: -------------------------------------------------------------------------------- 1 | com.itangcent.ai.OpenAIService 2 | com.itangcent.ai.DeepSeekService 3 | com.itangcent.ai.LocalLLMService -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.common.logger.ILogger: -------------------------------------------------------------------------------- 1 | #com.itangcent.debug.LoggerCollector -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.common.spi.SetupAble: -------------------------------------------------------------------------------- 1 | com.itangcent.intellij.spi.IdeaAutoInject 2 | com.itangcent.intellij.tip.OnlyOnceInContextTipSetup 3 | com.itangcent.intellij.jvm.kotlin.KotlinAutoInject 4 | com.itangcent.idea.psi.DisableDocSupport 5 | com.itangcent.suv.http.HttpClientScriptInterceptorSupport 6 | com.itangcent.intellij.context.AutoClearSupporter 7 | com.itangcent.ai.AIServiceCacheSupport -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.condition.Condition: -------------------------------------------------------------------------------- 1 | com.itangcent.idea.condition.OnClassCondition 2 | com.itangcent.idea.condition.OnMissingClassCondition 3 | com.itangcent.idea.plugin.api.export.condition.OnChannelCondition 4 | com.itangcent.idea.plugin.api.export.condition.OnDocCondition 5 | com.itangcent.idea.plugin.api.export.condition.OnSimpleCondition 6 | com.itangcent.idea.plugin.condition.OnSettingCondition -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.idea.plugin.Initializer: -------------------------------------------------------------------------------- 1 | com.itangcent.idea.plugin.settings.EnumProcessInitializer -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.idea.plugin.api.export.core.ClassExporter: -------------------------------------------------------------------------------- 1 | com.itangcent.idea.plugin.api.export.spring.SimpleSpringRequestClassExporter 2 | com.itangcent.idea.plugin.api.export.spring.SpringRequestClassExporter 3 | com.itangcent.idea.plugin.api.export.spring.ActuatorEndpointExporter 4 | com.itangcent.idea.plugin.api.export.feign.FeignRequestClassExporter 5 | com.itangcent.idea.plugin.api.export.feign.SimpleFeignRequestClassExporter 6 | com.itangcent.idea.plugin.api.export.jaxrs.JAXRSRequestClassExporter 7 | com.itangcent.idea.plugin.api.export.jaxrs.SimpleJAXRSRequestClassExporter 8 | com.itangcent.idea.plugin.api.export.generic.GenericMethodDocClassExporter 9 | com.itangcent.idea.plugin.api.export.generic.GenericRequestClassExporter 10 | com.itangcent.idea.plugin.api.export.generic.SimpleGenericMethodDocClassExporter 11 | com.itangcent.idea.plugin.api.export.generic.SimpleGenericRequestClassExporter -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.idea.plugin.api.export.core.MethodDocBuilderListener: -------------------------------------------------------------------------------- 1 | com.itangcent.idea.plugin.api.export.core.DefaultMethodDocBuilderListener 2 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.idea.plugin.api.export.core.RequestBuilderListener: -------------------------------------------------------------------------------- 1 | com.itangcent.idea.plugin.api.export.core.DefaultRequestBuilderListener 2 | com.itangcent.idea.plugin.api.export.postman.PostmanRequestBuilderListener 3 | com.itangcent.idea.plugin.api.export.translation.TranslationRequestBuilderListener 4 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.idea.plugin.api.export.spring.SpringControllerAnnotationResolver: -------------------------------------------------------------------------------- 1 | com.itangcent.idea.plugin.api.export.spring.StandardSpringControllerAnnotationResolver 2 | com.itangcent.idea.plugin.api.export.spring.CustomSpringControllerAnnotationResolver 3 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.idea.plugin.api.export.spring.SpringRequestMappingResolver: -------------------------------------------------------------------------------- 1 | com.itangcent.idea.plugin.api.export.spring.StandardSpringRequestMappingResolver 2 | com.itangcent.idea.plugin.api.export.spring.CustomSpringRequestMappingResolver 3 | com.itangcent.idea.plugin.api.export.feign.RequestLineRequestMappingResolver -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.intellij.CustomInfo: -------------------------------------------------------------------------------- 1 | com.itangcent.idea.plugin.CustomInfoImpl -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.intellij.config.ConfigProvider: -------------------------------------------------------------------------------- 1 | com.itangcent.idea.plugin.config.RecommendConfigProvider 2 | com.itangcent.idea.plugin.config.BuiltinConfigProvider 3 | com.itangcent.idea.plugin.config.RemoteConfigProvider 4 | com.itangcent.idea.plugin.config.RuntimeConfigProvider 5 | com.itangcent.idea.plugin.api.export.core.EasyApiConfigProvider 6 | com.itangcent.idea.plugin.api.export.postman.PostmanConfigProvider 7 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/META-INF/services/com.itangcent.suv.http.HttpClientProvider: -------------------------------------------------------------------------------- 1 | com.itangcent.suv.http.ApacheHttpClientProvider 2 | com.itangcent.suv.http.OkHttpClientProvider -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/class.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/collapseall.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/export.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/import.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/method.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/module.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/moduleGroup.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/ok.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/refresh.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/run.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/upFolder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /idea-plugin/src/main/resources/assets/webFolder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/condition/DefaultConditionEvaluatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.condition 2 | 3 | import com.itangcent.intellij.context.ActionContext 4 | import org.junit.jupiter.api.Test 5 | import org.mockito.kotlin.mock 6 | import kotlin.reflect.KClass 7 | import kotlin.test.assertFalse 8 | import kotlin.test.assertTrue 9 | 10 | /** 11 | * Test case of [DefaultConditionEvaluator] 12 | */ 13 | internal class DefaultConditionEvaluatorTest { 14 | 15 | @Test 16 | fun matches() { 17 | val actionContext = mock() 18 | MyCondition.matches = false 19 | assertFalse(DefaultConditionEvaluator().matches(actionContext, FakeBeanService::class)) 20 | MyCondition.matches = true 21 | assertTrue(DefaultConditionEvaluator().matches(actionContext, FakeBeanService::class)) 22 | } 23 | } 24 | 25 | @Conditional(MyCondition::class) 26 | class FakeBeanService { 27 | 28 | } 29 | 30 | class MyCondition : Condition { 31 | override fun matches(actionContext: ActionContext, beanClass: KClass<*>): Boolean { 32 | return matches 33 | } 34 | 35 | companion object { 36 | var matches = false 37 | } 38 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/debug/LoggerCollectorTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.debug 2 | 3 | import com.itangcent.intellij.context.ActionContextBuilder 4 | import com.itangcent.intellij.extend.guice.with 5 | import com.itangcent.intellij.logger.Logger 6 | import com.itangcent.mock.BaseContextTest 7 | import org.junit.jupiter.api.Test 8 | import kotlin.test.assertEquals 9 | 10 | /** 11 | * Test case with [LoggerCollector] 12 | */ 13 | internal class LoggerCollectorTest : BaseContextTest() { 14 | 15 | override fun bind(builder: ActionContextBuilder) { 16 | super.bind(builder) 17 | builder.bind(Logger::class) { it.with(LoggerCollector::class) } 18 | } 19 | 20 | @Test 21 | fun testLog() { 22 | logger.debug("hello") 23 | logger.info("world") 24 | assertEquals( 25 | "[DEBUG]\thello\n" + 26 | "[INFO]\tworld\n", LoggerCollector.getLog() 27 | ) 28 | } 29 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/condition/OnClassConditionTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.condition 2 | 3 | import com.itangcent.idea.condition.annotation.ConditionOnClass 4 | import com.itangcent.testFramework.PluginContextLightCodeInsightFixtureTestCase 5 | 6 | /** 7 | * Test case of [OnClassCondition] 8 | */ 9 | internal class OnClassConditionTest : PluginContextLightCodeInsightFixtureTestCase() { 10 | 11 | override fun beforeBind() { 12 | super.beforeBind() 13 | loadClass("spring/RequestMapping.java") 14 | } 15 | 16 | fun testMatches() { 17 | val onClassCondition = OnClassCondition() 18 | assertTrue(onClassCondition.matches(actionContext, ConditionOnRequestMapping::class)) 19 | assertFalse(onClassCondition.matches(actionContext, ConditionOnRestController::class)) 20 | } 21 | 22 | @ConditionOnClass("org.springframework.web.bind.annotation.RequestMapping") 23 | class ConditionOnRequestMapping 24 | 25 | @ConditionOnClass("org.springframework.web.bind.annotation.RestController") 26 | class ConditionOnRestController 27 | } 28 | -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/condition/OnMissingClassConditionTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.condition 2 | 3 | import com.itangcent.idea.condition.annotation.ConditionOnMissingClass 4 | import com.itangcent.testFramework.PluginContextLightCodeInsightFixtureTestCase 5 | 6 | /** 7 | * Test case of [OnMissingClassCondition] 8 | */ 9 | internal class OnMissingClassConditionTest : PluginContextLightCodeInsightFixtureTestCase() { 10 | 11 | override fun beforeBind() { 12 | super.beforeBind() 13 | loadClass("spring/RequestMapping.java") 14 | } 15 | 16 | fun testMatches() { 17 | val onMissingClassCondition = OnMissingClassCondition() 18 | assertFalse(onMissingClassCondition.matches(actionContext, ConditionOnRequestMapping::class)) 19 | assertTrue(onMissingClassCondition.matches(actionContext, ConditionOnRestController::class)) 20 | } 21 | 22 | @ConditionOnMissingClass("org.springframework.web.bind.annotation.RequestMapping") 23 | class ConditionOnRequestMapping 24 | 25 | @ConditionOnMissingClass("org.springframework.web.bind.annotation.RestController") 26 | class ConditionOnRestController 27 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/CustomInfoImplTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin 2 | 3 | import com.itangcent.common.spi.SpiUtils 4 | import com.itangcent.intellij.CustomInfo 5 | import org.junit.jupiter.api.Assertions.assertEquals 6 | import org.junit.jupiter.api.Test 7 | 8 | internal class CustomInfoImplTest { 9 | 10 | @Test 11 | fun pluginName() { 12 | assertEquals("easy-api", SpiUtils.loadService(CustomInfo::class) 13 | !!.pluginName()) 14 | } 15 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/core/AdditionalParseHelperTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.google.inject.Inject 4 | import com.itangcent.intellij.context.ActionContextBuilder 5 | import com.itangcent.intellij.extend.guice.with 6 | import com.itangcent.mock.BaseContextTest 7 | import kotlin.reflect.KClass 8 | 9 | /** 10 | * Test case with [AdditionalParseHelper] 11 | */ 12 | abstract class AdditionalParseHelperTest : BaseContextTest() { 13 | 14 | @Inject 15 | protected lateinit var additionalParseHelper: AdditionalParseHelper 16 | 17 | abstract val additionalParseHelperClass: KClass 18 | 19 | override fun bind(builder: ActionContextBuilder) { 20 | super.bind(builder) 21 | builder.bind(AdditionalParseHelper::class) { it.with(additionalParseHelperClass) } 22 | } 23 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigProviderTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.core 2 | 3 | import com.itangcent.intellij.config.ConfigProvider 4 | import com.itangcent.intellij.config.ConfigProviderTest 5 | import org.junit.jupiter.api.Test 6 | import kotlin.reflect.KClass 7 | import kotlin.test.assertEquals 8 | 9 | /** 10 | * Test case of [EasyApiConfigProvider] 11 | */ 12 | internal class EasyApiConfigProviderTest : ConfigProviderTest() { 13 | override val configProviderClass: KClass 14 | get() = EasyApiConfigProvider::class 15 | 16 | @Test 17 | fun testConfig() { 18 | assertEquals( 19 | resourceId("config/a/.easy.api.config") + "\n" + 20 | resourceId("config/a/.easy.api.yml") + "\n" + 21 | resourceId("config/a/.easy.api.yaml") + "\n" + 22 | resourceId("config/.easy.api.config") + "\n" + 23 | resourceId("config/.easy.api.yml") + "\n" + 24 | resourceId("config/.easy.api.yaml"), 25 | configProvider.loadConfig().joinToString("\n") { it.id }) 26 | } 27 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanWorkspaceTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.api.export.postman 2 | 3 | import com.itangcent.idea.plugin.api.export.postman.Emojis.PERSONAL 4 | import com.itangcent.idea.plugin.api.export.postman.Emojis.TEAM 5 | import org.junit.jupiter.api.Assertions.assertEquals 6 | import org.junit.jupiter.api.Assertions.assertNull 7 | import org.junit.jupiter.api.Test 8 | 9 | /** 10 | * Test case of [PostmanWorkspace] 11 | */ 12 | internal class PostmanWorkspaceTest { 13 | 14 | @Test 15 | fun nameWithType() { 16 | val postmanWorkspace = PostmanWorkspace("001", null, null) 17 | assertNull(postmanWorkspace.nameWithType()) 18 | postmanWorkspace.name = "My Workspace" 19 | assertEquals("My Workspace", postmanWorkspace.nameWithType()) 20 | postmanWorkspace.type = "team" 21 | assertEquals("${TEAM}My Workspace", postmanWorkspace.nameWithType()) 22 | postmanWorkspace.type = "personal" 23 | assertEquals("${PERSONAL}My Workspace", postmanWorkspace.nameWithType()) 24 | } 25 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/rule/ScriptExplicitClassContextTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.rule 2 | 3 | import com.google.inject.Inject 4 | import com.intellij.psi.PsiClass 5 | import com.itangcent.idea.plugin.rule.ScriptRuleParser.ScriptClassContext 6 | import com.itangcent.idea.plugin.rule.ScriptRuleParser.ScriptExplicitClassContext 7 | import com.itangcent.intellij.jvm.DuckTypeHelper 8 | 9 | /** 10 | * Test case of [ScriptExplicitClassContext] 11 | */ 12 | class ScriptExplicitClassContextTest : ScriptClassContextBaseTest() { 13 | 14 | @Inject 15 | private lateinit var duckTypeHelper: DuckTypeHelper 16 | 17 | override fun PsiClass.asClassContext(): ScriptClassContext { 18 | return ruleParser.contextOf(duckTypeHelper.explicit(this), this) as ScriptClassContext 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/rule/ScriptPsiClassContextTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.rule 2 | 3 | import com.intellij.psi.PsiClass 4 | import com.itangcent.idea.plugin.rule.ScriptRuleParser.ScriptClassContext 5 | import com.itangcent.idea.plugin.rule.ScriptRuleParser.ScriptPsiClassContext 6 | 7 | /** 8 | * Test case of [ScriptPsiClassContext] 9 | */ 10 | class ScriptPsiClassContextTest : ScriptClassContextBaseTest() { 11 | 12 | override fun PsiClass.asClassContext(): ScriptClassContext { 13 | return ruleParser.contextOf(this, this) as ScriptClassContext 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/rule/ScriptPsiTypeContextTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.rule 2 | 3 | import com.intellij.psi.PsiClass 4 | import com.intellij.psi.util.PsiTypesUtil 5 | import com.itangcent.idea.plugin.rule.ScriptRuleParser.ScriptClassContext 6 | import com.itangcent.idea.plugin.rule.ScriptRuleParser.ScriptPsiTypeContext 7 | 8 | /** 9 | * Test case of [ScriptPsiTypeContext] 10 | */ 11 | class ScriptPsiTypeContextTest : ScriptClassContextBaseTest() { 12 | 13 | override fun PsiClass.asClassContext(): ScriptClassContext { 14 | return ruleParser.contextOf(PsiTypesUtil.getClassType(this), this) as ScriptClassContext 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/settings/EventRecordsTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings 2 | 3 | import com.itangcent.testFramework.PluginContextLightCodeInsightFixtureTestCase 4 | 5 | /** 6 | * Test case of [EventRecords] 7 | */ 8 | internal class EventRecordsTest : PluginContextLightCodeInsightFixtureTestCase() { 9 | 10 | fun testRecord() { 11 | assertEquals(EventRecords.getRecord("com.itangcent.test.record"), 0) 12 | assertEquals(EventRecords.record("com.itangcent.test.record"), 1) 13 | assertEquals(EventRecords.getRecord("com.itangcent.test.record"), 1) 14 | assertEquals(EventRecords.record("com.itangcent.test.record"), 2) 15 | assertEquals(EventRecords.getRecord("com.itangcent.test.record"), 2) 16 | } 17 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/settings/SettingsTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings 2 | 3 | import org.junit.jupiter.api.Test 4 | 5 | /** 6 | * Test case of [Settings] 7 | */ 8 | internal class SettingsTest { 9 | 10 | @Test 11 | fun testCETH() { 12 | val original = Settings() 13 | original.pullNewestDataBefore = true 14 | 15 | ETHUtils.testCETH(original) { copy() } 16 | } 17 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/settings/helper/BuiltInConfigSettingsHelperTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings.helper 2 | 3 | import com.google.inject.Inject 4 | import org.junit.jupiter.api.Test 5 | import kotlin.test.assertEquals 6 | 7 | /** 8 | * Test case of [BuiltInConfigSettingsHelper] 9 | */ 10 | internal class BuiltInConfigSettingsHelperTest : SettingsHelperTest() { 11 | 12 | @Inject 13 | private lateinit var builtInConfigSettingsHelper: BuiltInConfigSettingsHelper 14 | 15 | @Test 16 | fun testBuiltInConfig() { 17 | settings.builtInConfig = "hello world" 18 | assertEquals("hello world", builtInConfigSettingsHelper.builtInConfig()) 19 | settings.builtInConfig = "test-demo" 20 | assertEquals("test-demo", builtInConfigSettingsHelper.builtInConfig()) 21 | } 22 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/settings/helper/SettingsHelperTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings.helper 2 | 3 | import com.itangcent.idea.plugin.settings.SettingBinder 4 | import com.itangcent.idea.plugin.settings.Settings 5 | import com.itangcent.intellij.context.ActionContextBuilder 6 | import com.itangcent.mock.AdvancedContextTest 7 | import com.itangcent.mock.SettingBinderAdaptor 8 | 9 | /** 10 | * Test case of [*SettingsHelper] 11 | */ 12 | abstract class SettingsHelperTest : AdvancedContextTest() { 13 | 14 | internal val settings = Settings() 15 | 16 | override fun bind(builder: ActionContextBuilder) { 17 | super.bind(builder) 18 | builder.bind(SettingBinder::class) { it.toInstance(SettingBinderAdaptor(settings)) } 19 | } 20 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/settings/helper/SupportSettingsHelperTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.settings.helper 2 | 3 | import com.google.inject.Inject 4 | import org.junit.jupiter.api.Test 5 | import kotlin.test.assertFalse 6 | import kotlin.test.assertTrue 7 | 8 | /** 9 | * Test case of [SupportSettingsHelper] 10 | */ 11 | internal class SupportSettingsHelperTest : SettingsHelperTest() { 12 | 13 | @Inject 14 | private lateinit var supportSettingsHelper: SupportSettingsHelper 15 | 16 | @Test 17 | fun testMethodDocEnable() { 18 | settings.methodDocEnable = true 19 | assertTrue(supportSettingsHelper.methodDocEnable()) 20 | settings.methodDocEnable = false 21 | assertFalse(supportSettingsHelper.methodDocEnable()) 22 | } 23 | 24 | @Test 25 | fun testGenericEnable() { 26 | settings.genericEnable = true 27 | assertTrue(supportSettingsHelper.genericEnable()) 28 | settings.genericEnable = false 29 | assertFalse(supportSettingsHelper.genericEnable()) 30 | } 31 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/utils/LocalStorageTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.utils 2 | 3 | /** 4 | * Test case of [LocalStorage] 5 | */ 6 | class LocalStorageTest : AbstractStorageTest() { 7 | override val storageClass = LocalStorage::class 8 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/utils/SessionStorageTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.plugin.utils 2 | 3 | /** 4 | * Test case of [SessionStorage] 5 | */ 6 | class SessionStorageTest : AbstractStorageTest() { 7 | override val storageClass = SessionStorage::class 8 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/psi/PsiMethodUtilTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.psi 2 | 3 | import com.intellij.psi.PsiClass 4 | import com.itangcent.testFramework.PluginContextLightCodeInsightFixtureTestCase 5 | import org.junit.Assert 6 | 7 | /** 8 | * Test case of [PsiMethodUtil] 9 | */ 10 | internal class PsiMethodUtilTest : PluginContextLightCodeInsightFixtureTestCase() { 11 | 12 | private lateinit var resultPsiClass: PsiClass 13 | private lateinit var iResultPsiClass: PsiClass 14 | 15 | override fun beforeBind() { 16 | super.beforeBind() 17 | 18 | iResultPsiClass = loadClass("model/IResult.java")!! 19 | resultPsiClass = loadClass("model/Result.java")!! 20 | } 21 | 22 | fun testIsSuperMethod() { 23 | assertTrue(PsiMethodUtil.isSuperMethod( 24 | resultPsiClass.methods.first { it.name == "getCode" }, 25 | iResultPsiClass.methods.first { it.name == "getCode" } 26 | )) 27 | assertFalse(PsiMethodUtil.isSuperMethod( 28 | resultPsiClass.methods.first { it.name == "fail" }, 29 | resultPsiClass.methods.last { it.name == "fail" } 30 | )) 31 | } 32 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/utils/ConfigurableLoggerTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.utils 2 | 3 | import com.itangcent.debug.LoggerCollector 4 | import com.itangcent.idea.plugin.settings.helper.CommonSettingsHelper 5 | import com.itangcent.logger.ConfigurableLogger 6 | import org.junit.jupiter.params.ParameterizedTest 7 | import org.junit.jupiter.params.provider.CsvSource 8 | import kotlin.test.assertEquals 9 | 10 | /** 11 | * Test case of [com.itangcent.logger.ConfigurableLogger] 12 | */ 13 | internal class ConfigurableLoggerTest { 14 | 15 | @ParameterizedTest 16 | @CsvSource( 17 | "VERBOSE,[TRACE]\ttrace[DEBUG]\tdebug[INFO]\tinfo[WARN]\twarn[ERROR]\terror[INFO]\tlog", 18 | "NORMAL,[INFO]\tinfo[WARN]\twarn[ERROR]\terror[INFO]\tlog", 19 | "QUIET,[ERROR]\terror", 20 | ) 21 | fun testLog(level: CommonSettingsHelper.VerbosityLevel, output: String) { 22 | val logger = ConfigurableLogger( 23 | LoggerCollector(), 24 | level.level 25 | ) 26 | logger.trace("trace") 27 | logger.debug("debug") 28 | logger.info("info") 29 | logger.warn("warn") 30 | logger.error("error") 31 | logger.log("log") 32 | assertEquals(output, LoggerCollector.getLog().replace("\n", "")) 33 | } 34 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/utils/DefaultSystemProviderTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.utils 2 | 3 | import com.google.inject.Inject 4 | import com.itangcent.intellij.context.ActionContextBuilder 5 | import com.itangcent.intellij.extend.guice.with 6 | import com.itangcent.mock.AdvancedContextTest 7 | import org.junit.jupiter.api.Test 8 | import kotlin.math.abs 9 | import kotlin.test.assertEquals 10 | import kotlin.test.assertTrue 11 | 12 | /** 13 | * Test case of [DefaultSystemProvider] 14 | */ 15 | internal class DefaultSystemProviderTest : AdvancedContextTest() { 16 | 17 | @Inject 18 | private lateinit var systemProvider: SystemProvider 19 | 20 | override fun bind(builder: ActionContextBuilder) { 21 | super.bind(builder) 22 | builder.bind(SystemProvider::class) { it.with(DefaultSystemProvider::class) } 23 | } 24 | 25 | @Test 26 | fun testCurrentTimeMillis() { 27 | assertTrue(abs(systemProvider.currentTimeMillis() - System.currentTimeMillis()) < 5) 28 | } 29 | 30 | @Test 31 | fun testRunTime() { 32 | assertEquals(Runtime.getRuntime(), systemProvider.runtime()) 33 | } 34 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/utils/IOUtilsTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.utils 2 | 3 | import org.junit.jupiter.api.Test 4 | 5 | 6 | /** 7 | * Test case for [IOUtils] 8 | */ 9 | class IOUtilsTest { 10 | 11 | @Test 12 | fun testGetEncodingName() { 13 | // assertEquals("UTF-8", IOUtils.getEncodingName("utf-8".toByteArray(Charsets.UTF_8))) 14 | } 15 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/idea/utils/ProjectHelperTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.idea.utils 2 | 3 | import com.itangcent.testFramework.ContextLightCodeInsightFixtureTestCase 4 | import org.junit.jupiter.api.Test 5 | 6 | /** 7 | * Test case for [ProjectHelper] 8 | */ 9 | internal class ProjectHelperTest : ContextLightCodeInsightFixtureTestCase() { 10 | 11 | fun testGetCurrentProject() { 12 | assertEquals(project, ProjectHelper.getCurrentProject(null)) 13 | } 14 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/intellij/extend/ThrottleKitTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.intellij.extend 2 | 3 | import com.itangcent.intellij.extend.rx.throttle 4 | import org.junit.jupiter.api.Assertions.assertFalse 5 | import org.junit.jupiter.api.Assertions.assertTrue 6 | import org.junit.jupiter.api.Test 7 | import org.junit.jupiter.api.assertTimeout 8 | import java.time.Duration 9 | 10 | 11 | /** 12 | * Test case for [ThrottleKit] 13 | */ 14 | class ThrottleKitTest { 15 | 16 | @Test 17 | fun testAcquireGreedy() { 18 | val throttle = throttle() 19 | throttle.acquire(1000) 20 | val now = System.currentTimeMillis() 21 | assertTimeout(Duration.ofMillis(10)) { throttle.acquire(1000) } 22 | assertFalse(throttle.acquire(1000)) 23 | throttle.acquireGreedy(1000) 24 | assertTrue(now + 99 <= System.currentTimeMillis()) 25 | Thread.sleep(1000) 26 | assertTrue(throttle.acquire(1000)) 27 | } 28 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/intellij/util/CacheAbleTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.intellij.util 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Test 5 | 6 | 7 | /** 8 | * Test case for [CacheAble] 9 | */ 10 | class CacheAbleTest { 11 | 12 | @Test 13 | fun testCache() { 14 | val cacheAble: CacheAble = DefaultCacheAle() 15 | 16 | assertEquals("str", cacheAble.cache("str") { "str" }) 17 | assertEquals("str", cacheAble.cache("str") { }) 18 | assertEquals("str", cacheAble.cache("str") { 1 }) 19 | 20 | var cnt = 0 21 | assertEquals("str", cacheAble.cache("str") { cnt++ }) 22 | assertEquals(0, cnt) 23 | 24 | assertEquals(null, cacheAble.cache("null") { null }) 25 | assertEquals(null, cacheAble.cache("null") { 1 }) 26 | } 27 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/intellij/util/FileTypeTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.intellij.util 2 | 3 | import com.itangcent.mock.BaseContextTest 4 | import org.junit.jupiter.api.Assertions.assertFalse 5 | import org.junit.jupiter.api.Assertions.assertTrue 6 | import org.junit.jupiter.api.Test 7 | 8 | /** 9 | * Test case of [FileType] 10 | */ 11 | internal class FileTypeTest : BaseContextTest() { 12 | 13 | @Test 14 | fun suffix() { 15 | assertTrue(FileType.acceptable("xxxx.java")) 16 | assertTrue(FileType.acceptable("xxxx.kt")) 17 | assertFalse(FileType.acceptable("xxxx.scala")) 18 | } 19 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/mock/ConstantModuleHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.mock 2 | 3 | import com.google.inject.Singleton 4 | import com.intellij.psi.PsiClass 5 | import com.intellij.psi.PsiFile 6 | import com.intellij.psi.PsiMethod 7 | import com.itangcent.idea.utils.ModuleHelper 8 | 9 | @Singleton 10 | class ConstantModuleHelper(private val module: String) : ModuleHelper { 11 | 12 | override fun findModule(resource: Any): String { 13 | return module 14 | } 15 | 16 | override fun findModule(psiMethod: PsiMethod): String { 17 | return module 18 | } 19 | 20 | override fun findModule(cls: PsiClass): String { 21 | return module 22 | } 23 | 24 | override fun findModule(psiFile: PsiFile): String { 25 | return module 26 | } 27 | 28 | override fun findModuleByPath(path: String?): String { 29 | return module 30 | } 31 | 32 | companion object { 33 | val INSTANCE = ConstantModuleHelper("test_default") 34 | } 35 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/mock/CrossPlatformKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.mock 2 | 3 | fun String.toUnixString(): String { 4 | if (LINE_SEPARATOR == "\n") { 5 | return this 6 | } 7 | return this.replace(LINE_SEPARATOR, "\n") 8 | } 9 | 10 | private val LINE_SEPARATOR = System.getProperty("line.separator") -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/mock/FakeExportContext.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.mock 2 | 3 | import com.intellij.psi.PsiElement 4 | import com.itangcent.idea.plugin.api.export.core.ExportContext 5 | import com.itangcent.idea.plugin.api.export.core.RootExportContext 6 | 7 | class FakeExportContext: ExportContext , RootExportContext() { 8 | override fun psi(): PsiElement { 9 | TODO("Not yet implemented") 10 | } 11 | 12 | companion object{ 13 | val INSTANCE = FakeExportContext() 14 | } 15 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/mock/ImmutableSystemProvider.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.mock 2 | 3 | import com.google.inject.Singleton 4 | import com.itangcent.idea.utils.SystemProvider 5 | 6 | @Singleton 7 | class ImmutableSystemProvider : SystemProvider { 8 | 9 | var currentTimeMillis: Long? = null 10 | 11 | var runtime: Runtime? = null 12 | 13 | constructor(currentTimeMillis: Long) { 14 | this.currentTimeMillis = currentTimeMillis 15 | } 16 | 17 | override fun currentTimeMillis(): Long { 18 | return currentTimeMillis ?: System.currentTimeMillis(); 19 | } 20 | 21 | override fun runtime(): Runtime { 22 | return runtime ?: Runtime.getRuntime() 23 | } 24 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/mock/MockKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.mock 2 | 3 | import com.itangcent.intellij.jvm.adapt.getterPropertyName 4 | import com.itangcent.intellij.jvm.adapt.maybeGetterMethodPropertyName 5 | import com.itangcent.intellij.jvm.adapt.maybeSetterMethodPropertyName 6 | import com.itangcent.intellij.jvm.adapt.setterPropertyName 7 | import org.mockito.stubbing.Answer 8 | 9 | inline fun any(t: T): T { 10 | org.mockito.kotlin.any() 11 | return t 12 | } 13 | 14 | fun mockFields(): Answer<*> { 15 | val data = hashMapOf() 16 | return Answer { 17 | val name = it.method.name 18 | if (name.maybeGetterMethodPropertyName()) { 19 | return@Answer data[name.getterPropertyName()] 20 | } else if (name.maybeSetterMethodPropertyName()) { 21 | data[name.setterPropertyName()] = it.arguments[0] 22 | return@Answer null 23 | } else { 24 | return@Answer null 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/mock/SettingBinderAdaptor.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.mock 2 | 3 | import com.google.inject.Singleton 4 | import com.itangcent.idea.plugin.settings.SettingBinder 5 | import com.itangcent.idea.plugin.settings.Settings 6 | 7 | @Singleton 8 | class SettingBinderAdaptor : SettingBinder { 9 | 10 | private var settings: Settings 11 | 12 | constructor(settings: Settings) { 13 | this.settings = settings 14 | } 15 | 16 | constructor() { 17 | this.settings = Settings() 18 | } 19 | 20 | override fun read(): Settings { 21 | return settings 22 | } 23 | 24 | override fun save(t: Settings?) { 25 | if (t != null) { 26 | this.settings = t 27 | } 28 | } 29 | 30 | override fun tryRead(): Settings? { 31 | return settings 32 | } 33 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/test/ActionContextKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.test 2 | 3 | import org.mockito.Mockito 4 | import org.mockito.kotlin.KStubbing 5 | import org.mockito.kotlin.mock 6 | import org.mockito.kotlin.stub 7 | import kotlin.reflect.KClass 8 | 9 | @Suppress("UNCHECKED_CAST") 10 | fun com.itangcent.intellij.context.ActionContextBuilder.mock(type: KClass<*>) { 11 | this.bindInstance(type as KClass, Mockito.mock(type.java) as Any) 12 | } 13 | 14 | @Suppress("UNCHECKED_CAST") 15 | fun com.itangcent.intellij.context.ActionContextBuilder.mock( 16 | type: KClass, 17 | mock: KStubbing.(T) -> Unit 18 | ) { 19 | val mockCls = type.java 20 | this.bindInstance(type as KClass, Mockito.mock(mockCls).also { 21 | KStubbing(it).mock(it) 22 | } as Any) 23 | } 24 | 25 | @Suppress("UNCHECKED_CAST") 26 | inline fun com.itangcent.intellij.context.ActionContextBuilder.mock( 27 | stubbing: KStubbing.(T) -> Unit 28 | ) { 29 | this.bindInstance( 30 | T::class as KClass, 31 | mock().stub(stubbing) as Any 32 | ) 33 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/test/AssertKits.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.test 2 | 3 | import kotlin.test.assertEquals 4 | import kotlin.test.assertTrue 5 | 6 | 7 | fun assertContentEquals(expected: Array, actual: Array?) { 8 | assertTrue(expected.contentEquals(actual)) 9 | } 10 | 11 | fun assertLinesEqualsIgnoreOrder(expected: String, actual: String) { 12 | val expectedLines = expected.lines() 13 | val actualLines = actual.lines() 14 | assertEquals(expectedLines.size, actualLines.size) 15 | assertEquals(expectedLines.sorted(), actualLines.sorted()) 16 | } 17 | 18 | fun assertLinesContain(expected: String, actual: String) { 19 | val expectedLines = expected.lines() 20 | val actualLines = actual.lines().toHashSet() 21 | assertTrue(actualLines.containsAll(expectedLines)) 22 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/test/ResultLoaderTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.test 2 | 3 | import org.junit.jupiter.api.Test 4 | import kotlin.test.assertEquals 5 | 6 | /** 7 | * Test case of [ResultLoader] 8 | */ 9 | internal class ResultLoaderTest { 10 | 11 | @Test 12 | fun testLoad() { 13 | assertEquals("asdfghjkl", ResultLoader.load()) 14 | assertEquals("123456789", ResultLoader.load("sub")) 15 | } 16 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/test/StringResource.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.test 2 | 3 | import com.itangcent.intellij.config.resource.Resource 4 | import java.io.InputStream 5 | import java.net.URL 6 | 7 | class StringResource( 8 | private val _url: String, 9 | private val str: String, 10 | ) : Resource() { 11 | override val url: URL 12 | get() = URL(_url) 13 | 14 | override val bytes: ByteArray 15 | get() = str.toByteArray(Charsets.UTF_8) 16 | 17 | override val content: String 18 | get() = str 19 | 20 | override val inputStream: InputStream 21 | get() = str.toByteArray(Charsets.UTF_8).inputStream() 22 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/testFramework/FileKit.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.testFramework 2 | 3 | import java.io.File 4 | import java.nio.file.Path 5 | 6 | private val separator = File.separator 7 | 8 | fun Path.sub(path: String): File { 9 | return File("$this/$path".r()) 10 | } 11 | 12 | fun String.sub(path: String): String { 13 | return "$this/$path".r() 14 | } 15 | 16 | fun String.escapeBackslash(): String { 17 | return this.replace("\\", "\\\\") 18 | } 19 | 20 | /** 21 | * redirect to real path 22 | */ 23 | fun String.r(): String { 24 | return this.replace("/", separator) 25 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/testFramework/PluginContextLightCodeInsightFixtureTestCase.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.testFramework 2 | 3 | import com.itangcent.idea.plugin.rule.SuvRuleParser 4 | import com.itangcent.idea.plugin.settings.SettingBinder 5 | import com.itangcent.idea.swing.MessagesHelper 6 | import com.itangcent.idea.utils.ModuleHelper 7 | import com.itangcent.intellij.config.rule.RuleParser 8 | import com.itangcent.intellij.context.ActionContextBuilder 9 | import com.itangcent.intellij.extend.guice.singleton 10 | import com.itangcent.intellij.extend.guice.with 11 | import com.itangcent.mock.ConstantModuleHelper 12 | import com.itangcent.mock.EmptyMessagesHelper 13 | import com.itangcent.mock.SettingBinderAdaptor 14 | 15 | 16 | abstract class PluginContextLightCodeInsightFixtureTestCase : ContextLightCodeInsightFixtureTestCase() { 17 | 18 | override fun bind(builder: ActionContextBuilder) { 19 | builder.bind(SettingBinder::class) { it.with(SettingBinderAdaptor::class) } 20 | builder.bind(RuleParser::class) { it.with(SuvRuleParser::class).singleton() } 21 | builder.bind(ModuleHelper::class) { it.toInstance(ConstantModuleHelper.INSTANCE) } 22 | builder.bind(MessagesHelper::class) { it.with(EmptyMessagesHelper::class).singleton() } 23 | } 24 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/utils/FileKitKtTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Test 5 | import org.junit.jupiter.api.condition.EnabledOnOs 6 | import org.junit.jupiter.api.condition.OS 7 | 8 | /** 9 | * Test case for [FileKit] 10 | */ 11 | class FileKitKtTest { 12 | @Test 13 | @EnabledOnOs(OS.WINDOWS, disabledReason = "Only for Windows") 14 | fun testLocalPath_windows() { 15 | val input = "/foo/bar" 16 | val expected = "\\foo\\bar" 17 | assertEquals(expected, input.localPath()) 18 | } 19 | 20 | @Test 21 | @EnabledOnOs(value = [OS.LINUX, OS.MAC], disabledReason = "Only for Linux and Mac") 22 | fun testLocalPath_linux() { 23 | val input = "/foo/bar" 24 | assertEquals(input, input.localPath()) 25 | } 26 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/utils/GiteeSupportTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Assertions.assertNull 5 | import org.junit.jupiter.api.Test 6 | 7 | /** 8 | * Test case for [GiteeSupport] 9 | * 10 | * @author tangcent 11 | */ 12 | internal class GiteeSupportTest { 13 | 14 | @Test 15 | fun testConvertUrlFromGithub() { 16 | val githubUrl = "https://raw.githubusercontent.com/user/project/file.txt" 17 | val expectedGiteeUrl = "https://gitee.com/user/project/raw/file.txt" 18 | 19 | val actualGiteeUrl = GiteeSupport.convertUrlFromGithub(githubUrl) 20 | 21 | assertEquals(expectedGiteeUrl, actualGiteeUrl) 22 | } 23 | 24 | @Test 25 | fun testInvalidUrl() { 26 | val invalidUrl = "some invalid url" 27 | val giteeUrl = GiteeSupport.convertUrlFromGithub(invalidUrl) 28 | 29 | assertNull(giteeUrl) 30 | } 31 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/utils/NonReentrantTest.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Test 5 | import org.junit.jupiter.api.assertThrows 6 | import kotlin.concurrent.thread 7 | 8 | class NonReentrantTest { 9 | 10 | @Test 11 | fun testCall() { 12 | assertThrows { 13 | NonReentrant.call("test") { 14 | call() 15 | } 16 | } 17 | assertEquals("yes", call()) 18 | 19 | val threadA = thread { 20 | NonReentrant.call("test") { 21 | Thread.sleep(1000) 22 | } 23 | } 24 | val threadB = thread { 25 | NonReentrant.call("test") { 26 | Thread.sleep(1000) 27 | } 28 | } 29 | threadA.join() 30 | threadB.join() 31 | } 32 | 33 | private fun call() = NonReentrant.call("test") { 34 | "yes" 35 | } 36 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/kotlin/com/itangcent/utils/WaitHelper.kt: -------------------------------------------------------------------------------- 1 | package com.itangcent.utils 2 | 3 | import kotlin.test.fail 4 | 5 | object WaitHelper { 6 | 7 | fun waitUtil(timeOut: Long, condition: () -> Boolean) { 8 | val t = System.currentTimeMillis() + timeOut 9 | while (true) { 10 | if (condition()) { 11 | return 12 | } 13 | if (System.currentTimeMillis() > t) { 14 | break 15 | } 16 | Thread.sleep(200) 17 | } 18 | fail() 19 | } 20 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/META-INF/services/com.itangcent.idea.icons.IconLoader: -------------------------------------------------------------------------------- 1 | com.itangcent.test.IconLoaderHeadlessSupport -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/META-INF/services/com.itangcent.spi.MyService: -------------------------------------------------------------------------------- 1 | com.itangcent.spi.MyService1 2 | com.itangcent.spi.MyService2 -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/annotation/MyController.java: -------------------------------------------------------------------------------- 1 | package api.annotation; 2 | 3 | import org.springframework.core.annotation.AliasFor; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | import java.lang.annotation.Documented; 7 | import java.lang.annotation.ElementType; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | 12 | @Target({ElementType.TYPE}) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Documented 15 | @RestController 16 | public @interface MyController { 17 | @AliasFor(annotation = RestController.class) 18 | String value() default ""; 19 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/annotation/Public.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.Target; 6 | 7 | import static java.lang.annotation.ElementType.METHOD; 8 | import static java.lang.annotation.ElementType.TYPE; 9 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 10 | 11 | /** 12 | * Announce the interface as public 13 | */ 14 | @Documented 15 | @Retention(RUNTIME) 16 | @Target({TYPE, METHOD}) 17 | public @interface Public { 18 | } 19 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/api/BaseController.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.api; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | 5 | @RequestMapping("/") 6 | public class BaseController { 7 | 8 | /** 9 | * current ctrl name 10 | * 11 | * @public 12 | */ 13 | @RequestMapping("/ctrl/name") 14 | public String ctrlName() { 15 | return getClass().getName(); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/api/CustomCtrl.java: -------------------------------------------------------------------------------- 1 | package api.annotation; 2 | 3 | import api.annotation.MyController; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @MyController 7 | public class CustomCtrl { 8 | 9 | @RequestMapping(value = "/hello") 10 | public String hello() { 11 | return "Hello, World!"; 12 | } 13 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/api/IUserApi.java: -------------------------------------------------------------------------------- 1 | 2 | package com.itangcent.api; 3 | 4 | 5 | import com.itangcent.model.Result; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | 10 | import java.util.ArrayList; 11 | 12 | /** 13 | * api interface 14 | */ 15 | @RequestMapping(value = "user") 16 | public interface IUserApi { 17 | 18 | @PostMapping(value = "/auth/loginAuth") 19 | Result loginAuth(@RequestBody Req req); 20 | 21 | /** 22 | * A default api 23 | * It is not necessary to implement it 24 | * 25 | * @param req request 26 | * @return response 27 | */ 28 | @PostMapping(value = "/default") 29 | default Result> defaultApi(@RequestBody List req) { 30 | return Result.success(new ArrayList<>()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/api/InferDemoCtrl.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.api; 2 | 3 | 4 | import com.itangcent.api.BaseController; 5 | import com.itangcent.model.Result; 6 | 7 | import java.util.HashMap; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * infer demo 14 | */ 15 | @RestController 16 | @RequestMapping(value = "infer") 17 | public class InferDemoCtrl extends BaseController { 18 | 19 | /** 20 | * Infer the response that contains the collection 21 | */ 22 | @RequestMapping(value = "/interWithCollection", method = RequestMethod.POST) 23 | public Object interWithCollection(@PathVariable("id") Long id) { 24 | List list = new LinkedList<>(); 25 | Map map = new HashMap<>(); 26 | map.put("key1", "string");//This is the key for the test 27 | map.put("key2", 666);//This is a test key valued 666 28 | Map value3 = new HashMap<>(); 29 | value3.put("subKey", "string");//This is the key of the child 30 | //This is a child for test 31 | map.put("key3", value3); 32 | list.add(map); 33 | return Result.success(list); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/api/MyCtrl.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.api; 2 | 3 | 4 | import com.itangcent.api.BaseController; 5 | import com.itangcent.model.Result; 6 | import org.springframework.web.bind.annotation.FakeMapping; 7 | import org.springframework.web.bind.annotation.MyPostMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | 11 | /** 12 | * demo for custom annotations 13 | */ 14 | @RestController 15 | public class MyCtrl extends BaseController { 16 | 17 | /** 18 | * post 19 | */ 20 | @MyPostMapping("/myPost") 21 | public Result post() { 22 | return Result.success("yes"); 23 | } 24 | 25 | /** 26 | * postWithParam 27 | */ 28 | @MyPostMapping(value = "/myPostWithParam", params = "name") 29 | public Result postWithParam() { 30 | return Result.success("yes"); 31 | } 32 | 33 | /** 34 | * fake 35 | */ 36 | @FakeMapping("/fake") 37 | public Result fake() { 38 | return Result.success("no"); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/api/NameCtrl.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.api; 2 | 3 | import com.itangcent.annotation.Public; 4 | import com.itangcent.api.BaseController; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | 7 | public class NameCtrl extends BaseController { 8 | 9 | @RequestMapping(value = "/nothing") 10 | public String nothing() { 11 | return "nothing"; 12 | } 13 | 14 | /** 15 | * say hello 16 | */ 17 | @Public 18 | @RequestMapping(value = "/greeting") 19 | public String oneLine() { 20 | return "hello world"; 21 | } 22 | 23 | /** 24 | * say hello 25 | * not update anything 26 | * just say hello 27 | */ 28 | @Public 29 | @RequestMapping(value = "/greeting") 30 | public String muiltLine() { 31 | return "hello world"; 32 | } 33 | 34 | /** 35 | * not update anything 36 | * just say hello 37 | * 38 | * @name say hello 39 | */ 40 | @Public 41 | @RequestMapping(value = "/greeting") 42 | public String muiltLine() { 43 | return "hello world"; 44 | } 45 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/api/UserApiImpl.java: -------------------------------------------------------------------------------- 1 | 2 | package com.itangcent.api; 3 | 4 | 5 | import com.itangcent.api.IUserApi; 6 | import com.itangcent.model.Model; 7 | import com.itangcent.model.Result; 8 | import com.itangcent.model.UserInfo; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * api interface 13 | */ 14 | @RestController 15 | public class UserApiImpl implements IUserApi { 16 | 17 | @Override 18 | public Result loginAuth(UserInfo userInfo) { 19 | return Result.success(userInfo); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/api/jaxrs/MyGet.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.jaxrs; 2 | 3 | import javax.ws.rs.HttpMethod; 4 | import java.lang.annotation.Documented; 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | @Target({ElementType.METHOD}) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @HttpMethod(HttpMethod.GET) 13 | @Documented 14 | public @interface MyGet { 15 | } 16 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/api/jaxrs/MyPut.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.jaxrs; 2 | 3 | import javax.ws.rs.PUT; 4 | import java.lang.annotation.Documented; 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | @Target({ElementType.METHOD}) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @PUT 13 | @Documented 14 | public @interface MyPut { 15 | } 16 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/cases/NestedClass.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.cases; 2 | 3 | public class NestedClass { 4 | 5 | public class InnerClassA { 6 | 7 | } 8 | 9 | public static class StaticInnerClassA { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/cases/NestedClassB.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.cases; 2 | 3 | public class NestedClassB { 4 | 5 | public class InnerClassB { 6 | 7 | } 8 | 9 | public static class StaticInnerClassB { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/client/UserClient.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.client; 2 | 3 | import com.itangcent.model.UserInfo; 4 | 5 | /** 6 | * rpc apis about user 7 | * access user info 8 | * 9 | * @module user 10 | */ 11 | public interface UserClient { 12 | 13 | /** 14 | * say hello 15 | * not update anything 16 | */ 17 | public String greeting(); 18 | 19 | 20 | /** 21 | * update username 22 | * 23 | * @param id user id 24 | * @param newName new user name 25 | * @param slogon personal slogon 26 | * @deprecated use {@link #update(UserInfo)} 27 | */ 28 | public UserInfo set(long id, String newName, 29 | String slogon, 30 | long times); 31 | 32 | 33 | /** 34 | * get user info 35 | * 36 | * @param id user id 37 | * @folder update-apis 38 | * @undone 39 | * @path /user/get 40 | */ 41 | @Deprecated 42 | public UserInfo get(Long id); 43 | 44 | /** 45 | * create new use 46 | */ 47 | public UserInfo add(UserInfo userInfo); 48 | 49 | /** 50 | * update user info 51 | */ 52 | public void update(UserInfo userInfo); 53 | } 54 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/.easy.api.config: -------------------------------------------------------------------------------- 1 | config.c=cc -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/.easy.api.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | a: ca -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/.easy.api.yml: -------------------------------------------------------------------------------- 1 | config: 2 | y: cy -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/.postman.config: -------------------------------------------------------------------------------- 1 | postman.config.c=cc -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/.postman.yaml: -------------------------------------------------------------------------------- 1 | postman: 2 | config: 3 | a: ca -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/.postman.yml: -------------------------------------------------------------------------------- 1 | postman: 2 | config: 3 | y: cy -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/a/.easy.api.config: -------------------------------------------------------------------------------- 1 | config.a.c=cac -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/a/.easy.api.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | a: 3 | a: caa -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/a/.easy.api.yml: -------------------------------------------------------------------------------- 1 | config: 2 | a: 3 | y: cay -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/a/.postman.config: -------------------------------------------------------------------------------- 1 | postman.config.a.c=cac -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/a/.postman.yaml: -------------------------------------------------------------------------------- 1 | postman: 2 | config: 3 | a: 4 | a: caa -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/config/a/.postman.yml: -------------------------------------------------------------------------------- 1 | postman: 2 | config: 3 | a: 4 | y: cay -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/constant/Add.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.constant; 2 | 3 | import javax.validation.groups.Default; 4 | 5 | public interface Add extends Default { 6 | } 7 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/constant/Numbers.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.constant; 2 | 3 | public interface Numbers { 4 | 5 | /** 6 | * one 7 | */ 8 | int ONE = 1; 9 | 10 | /** 11 | * two 12 | */ 13 | int TWO = 2; 14 | 15 | /** 16 | * three 17 | */ 18 | int THREE = 3; 19 | 20 | /** 21 | * four 22 | */ 23 | int FOUR = 4; 24 | 25 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/constant/Update.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.constant; 2 | 3 | import javax.validation.groups.Default; 4 | 5 | public interface Update extends Default { 6 | } 7 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/constant/UserType.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.constant; 2 | 3 | /** 4 | * type of user 5 | */ 6 | public enum UserType { 7 | //administration 8 | ADMIN(1, "ADMINISTRATION"), 9 | 10 | //a person, an animal or a plant 11 | MEM(2, "MEMBER"), 12 | 13 | //Anonymous visitor 14 | GUEST(3, "ANONYMOUS"); 15 | 16 | private int type;//user type 17 | 18 | private String desc; 19 | 20 | public int getType() { 21 | return type; 22 | } 23 | 24 | public String getDesc() { 25 | return desc; 26 | } 27 | 28 | UserType(int type, String desc) { 29 | this.type = type; 30 | this.desc = desc; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/constant/UserTypeConstant.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.constant; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * user type 7 | */ 8 | public class UserTypeConstant implements Serializable { 9 | 10 | private static final long serialVersionUID = -4607862808303533196L; 11 | 12 | public static final int ADMIN = 1;//administrator 13 | public static final int MEMBER = 2;//normal member 14 | public static final int GUEST = 3;//tourist 15 | 16 | } 17 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/demo.properties: -------------------------------------------------------------------------------- 1 | token=111111 -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/jaxrs/OPTIONS.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0, which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the 10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, 11 | * version 2 with the GNU Classpath Exception, which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | */ 16 | package javax.ws.rs; 17 | 18 | import java.lang.annotation.*; 19 | 20 | /** 21 | * Indicates that the annotated method responds to HTTP OPTIONS requests. 22 | * 23 | * @author Paul Sandoz 24 | * @author Marc Hadley 25 | * @see HttpMethod 26 | * @since 1.1 27 | */ 28 | @Target({ElementType.METHOD}) 29 | @Retention(RetentionPolicy.RUNTIME) 30 | @HttpMethod(HttpMethod.OPTIONS) 31 | @Documented 32 | public @interface OPTIONS { 33 | } 34 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/jdk/Deprecated.fava: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | */ 25 | 26 | package java.lang; 27 | 28 | import java.lang.annotation.Documented; 29 | import java.lang.annotation.Retention; 30 | import java.lang.annotation.RetentionPolicy; 31 | import java.lang.annotation.Target; 32 | 33 | import static java.lang.annotation.ElementType.*; 34 | 35 | /** 36 | * A program element annotated @Deprecated is one that programmers 37 | * are discouraged from using, typically because it is dangerous, 38 | * or because a better alternative exists. Compilers warn when a 39 | * deprecated program element is used or overridden in non-deprecated code. 40 | * 41 | * @author Neal Gafter 42 | * @since 1.5 43 | * @jls 9.6.3.6 @Deprecated 44 | */ 45 | @Documented 46 | @Retention(RetentionPolicy.RUNTIME) 47 | @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) 48 | public @interface Deprecated { 49 | } 50 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/model/CustomMap.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.model; 2 | 3 | import java.util.HashMap; 4 | 5 | public class CustomMap extends HashMap { 6 | 7 | private String a; 8 | 9 | public String getA() { 10 | return a; 11 | } 12 | 13 | public void setA(String a) { 14 | this.a = a; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/model/IResult.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.model; 2 | 3 | public interface IResult { 4 | Integer getCode(); 5 | 6 | String getMsg(); 7 | } 8 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/model/PageRequest.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.model; 2 | 3 | import com.itangcent.model.UserInfo; 4 | 5 | import java.util.List; 6 | 7 | public class PageRequest { 8 | 9 | private String size; 10 | 11 | private UserInfo user; 12 | 13 | private List users; 14 | 15 | private T t; 16 | 17 | public String getSize() { 18 | return size; 19 | } 20 | 21 | public void setSize(String size) { 22 | this.size = size; 23 | } 24 | 25 | public UserInfo getUser() { 26 | return user; 27 | } 28 | 29 | public void setUser(UserInfo user) { 30 | this.user = user; 31 | } 32 | 33 | public List getUsers() { 34 | return users; 35 | } 36 | 37 | public void setUsers(List users) { 38 | this.users = users; 39 | } 40 | 41 | public T getT() { 42 | return t; 43 | } 44 | 45 | public void setT(T t) { 46 | this.t = t; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/model/Root.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.model; 2 | 3 | import com.itangcent.model.Node; 4 | 5 | import java.util.List; 6 | 7 | public class Root { 8 | 9 | /** 10 | * primary key 11 | */ 12 | private String id; 13 | 14 | /** 15 | * sub nodes 16 | */ 17 | private List children; 18 | 19 | public Integer getValue() { 20 | return value; 21 | } 22 | 23 | public void setValue(Integer value) { 24 | this.value = value; 25 | } 26 | 27 | public List getChildren() { 28 | return children; 29 | } 30 | 31 | public void setChildren(List children) { 32 | this.children = children; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/model/SubModel.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.model; 2 | 3 | import com.itangcent.model.Model; 4 | 5 | class SubModel extends Model { 6 | 7 | private String subA; 8 | 9 | /** 10 | * @order 100 11 | */ 12 | private String subShouldBeLast; 13 | 14 | private String subB; 15 | 16 | /** 17 | * @order 0 18 | */ 19 | private String subShouldBeFirst; 20 | } -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/model/ValidationGroupedDemoDto.java: -------------------------------------------------------------------------------- 1 | package com.itangcent.model; 2 | 3 | import com.itangcent.constant.Add; 4 | import com.itangcent.constant.Update; 5 | 6 | import javax.validation.constraints.NotEmpty; 7 | import javax.validation.constraints.NotNull; 8 | 9 | public class ValidationGroupedDemoDto { 10 | 11 | @NotNull(groups = {Add.class}) 12 | private String strForAdd; 13 | 14 | @NotEmpty(groups = Update.class) 15 | private String notEmptyForUpdate; 16 | 17 | public String getStrForAdd() { 18 | return strForAdd; 19 | } 20 | 21 | public void setStrForAdd(String strForAdd) { 22 | this.strForAdd = strForAdd; 23 | } 24 | 25 | public String getNotEmptyForUpdate() { 26 | return notEmptyForUpdate; 27 | } 28 | 29 | public void setNotEmptyForUpdate(String notEmptyForUpdate) { 30 | this.notEmptyForUpdate = notEmptyForUpdate; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.api.call.ApiCallerTest.ExportFailedApiCallerTest.txt: -------------------------------------------------------------------------------- 1 | [INFO] Starting API export process... 2 | [ERROR] Apis exported failed 3 | [TRACE] java.lang.RuntimeException: export time out 4 | 5 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.api.export.curl.CurlExporterTest.txt: -------------------------------------------------------------------------------- 1 | ## current ctrl name 2 | ```bash 3 | curl -X GET http://localhost:8080/user/ctrl/name 4 | ``` 5 | 6 | --- 7 | 8 | ## say hello 9 | ```bash 10 | curl -X GET http://localhost:8080/user/greeting 11 | ``` 12 | 13 | --- 14 | 15 | ## get user info 16 | ```bash 17 | curl -X GET http://localhost:8080/user/get/{id}?id= 18 | ``` 19 | 20 | --- 21 | 22 | ## create an user 23 | ```bash 24 | curl -X POST -H 'Content-Type: application/json' -d '{ 25 | "id": 0, 26 | "type": 0, 27 | "name": "", 28 | "age": 0, 29 | "sex": 0, 30 | "birthDay": "", 31 | "regtime": "" 32 | }' http://localhost:8080/user/add 33 | ``` 34 | 35 | --- 36 | 37 | ## update user info 38 | ```bash 39 | curl -X PUT -H 'Content-Type: multipart/form-data' -F 'id=' -F 'type=' -F 'name=' -F 'age=' -F 'sex=' -F 'birthDay=' -F 'regtime=' http://localhost:8080/user/update 40 | ``` -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.api.export.generic.GenericMethodDocClassExporterTest.txt: -------------------------------------------------------------------------------- 1 | [INFO] search api from: com.itangcent.api.UserCtrl 2 | [INFO] before parse class:com.itangcent.api.UserCtrl 3 | [INFO] before parse method:com.itangcent.api.UserCtrl#ctrlName 4 | [INFO] after parse method:com.itangcent.api.UserCtrl#ctrlName 5 | [INFO] before parse method:com.itangcent.api.UserCtrl#greeting 6 | [INFO] after parse method:com.itangcent.api.UserCtrl#greeting 7 | [INFO] before parse method:com.itangcent.api.UserCtrl#get 8 | [INFO] after parse method:com.itangcent.api.UserCtrl#get 9 | [INFO] before parse method:com.itangcent.api.UserCtrl#create 10 | [INFO] after parse method:com.itangcent.api.UserCtrl#create 11 | [INFO] before parse method:com.itangcent.api.UserCtrl#update 12 | [INFO] after parse method:com.itangcent.api.UserCtrl#update 13 | [INFO] after parse class:com.itangcent.api.UserCtrl 14 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.api.export.postman.PostmanSpringRequestClassExporterTest.txt: -------------------------------------------------------------------------------- 1 | [INFO] search api from: com.itangcent.api.UserCtrl 2 | [INFO] before parse class:com.itangcent.api.UserCtrl 3 | [INFO] before parse method:com.itangcent.api.UserCtrl#ctrlName 4 | [INFO] after parse method:com.itangcent.api.UserCtrl#ctrlName 5 | [INFO] before parse method:com.itangcent.api.UserCtrl#greeting 6 | [INFO] after parse method:com.itangcent.api.UserCtrl#greeting 7 | [INFO] before parse method:com.itangcent.api.UserCtrl#get 8 | [INFO] try infer return type of method[com.itangcent.api.UserCtrl#get(java.lang.Long)] 9 | [INFO] after parse method:com.itangcent.api.UserCtrl#get 10 | [INFO] before parse method:com.itangcent.api.UserCtrl#create 11 | [INFO] after parse method:com.itangcent.api.UserCtrl#create 12 | [INFO] before parse method:com.itangcent.api.UserCtrl#update 13 | [INFO] after parse method:com.itangcent.api.UserCtrl#update 14 | [INFO] after parse class:com.itangcent.api.UserCtrl 15 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.api.export.spring.SpringRequestClassExporterTest.testExportFromUserApi.txt: -------------------------------------------------------------------------------- 1 | [INFO] search api from: com.itangcent.api.UserApiImpl 2 | [INFO] before parse class:com.itangcent.api.UserApiImpl 3 | [INFO] before parse method:com.itangcent.api.UserApiImpl#loginAuth 4 | [INFO] before parse param:req 5 | [INFO] after parse param:req 6 | [INFO] before parse param:req 7 | [INFO] after parse param:req 8 | [INFO] after parse method:com.itangcent.api.UserApiImpl#loginAuth 9 | [INFO] before parse method:com.itangcent.api.UserApiImpl#defaultApi 10 | [INFO] before parse param:req 11 | [INFO] after parse param:req 12 | [INFO] try infer return type of method[com.itangcent.api.IUserApi#defaultApi(List)] 13 | [WARN] error to resolve class:Res 14 | [INFO] after parse method:com.itangcent.api.UserApiImpl#defaultApi 15 | [INFO] after parse class:com.itangcent.api.UserApiImpl 16 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.EmptyRecommendEnhancedConfigReaderTest.log.txt: -------------------------------------------------------------------------------- 1 | [DEBUG] Even useRecommendConfig was true, but no recommend config be selected! 2 | 3 | If you need to enable the built-in recommended configuration.Go to [Preference -> Other Setting -> EasyApi -> Recommend] 4 | [DEBUG] Even useRecommendConfig was true, but no recommend config be selected! 5 | 6 | If you need to enable the built-in recommended configuration.Go to [Preference -> Other Setting -> EasyApi -> Recommend] 7 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.foreach.field.txt: -------------------------------------------------------------------------------- 1 | field.ignore=groovy:!it.containingClass().name().startsWith("java.lang")&&it.defineClass().name().startsWith("java.lang") 2 | field.name=@com.fasterxml.jackson.annotation.JsonProperty#value 3 | field.ignore=@com.fasterxml.jackson.annotation.JsonIgnore#value 4 | field.name=@com.google.gson.annotations.SerializedName#value 5 | field.ignore=!@com.google.gson.annotations.Expose#serialize 6 | field.ignore=groovy:it.hasModifier("transient") 7 | field.required=@org.springframework.lang.NonNull 8 | field.required=@jakarta.validation.constraints.NotBlank 9 | field.required=@jakarta.validation.constraints.NotNull 10 | field.required=@jakarta.validation.constraints.NotEmpty 11 | field.name=@com.alibaba.fastjson.annotation.JSONField#value 12 | field.ignore=groovy: 13 | def prefixList = it.type().name().tokenize(/[<>,]/).collect{ 14 | it.tokenize('.').inject([]) { acc, val -> acc << (acc ? "${acc.last()}.${val}" : val) } 15 | }.flatten() 16 | def ignored = config.getValues("ignored.classes_or_packages").collect{ 17 | it.tokenize(',').collect { it.trim() }.findAll { it } 18 | }.flatten() 19 | return !prefixList.intersect(ignored).isEmpty() -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.foreach.field.txt: -------------------------------------------------------------------------------- 1 | field.name=@com.fasterxml.jackson.annotation.JsonProperty#value 2 | field.ignore=@com.fasterxml.jackson.annotation.JsonIgnore#value 3 | field.name=@com.google.gson.annotations.SerializedName#value 4 | field.ignore=!@com.google.gson.annotations.Expose#serialize 5 | field.ignore=groovy:it.hasModifier("transient") 6 | field.required=@org.springframework.lang.NonNull 7 | field.required=@jakarta.validation.constraints.NotBlank 8 | field.required=@jakarta.validation.constraints.NotNull 9 | field.required=@jakarta.validation.constraints.NotEmpty 10 | field.name=@com.alibaba.fastjson.annotation.JSONField#value 11 | field.ignore=groovy: 12 | def prefixList = it.type().name().tokenize(/[<>,]/).collect{ 13 | it.tokenize('.').inject([]) { acc, val -> acc << (acc ? "${acc.last()}.${val}" : val) } 14 | }.flatten() 15 | def ignored = config.getValues("ignored.classes_or_packages").collect{ 16 | it.tokenize(',').collect { it.trim() }.findAll { it } 17 | }.flatten() 18 | return !prefixList.intersect(ignored).isEmpty() -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.rule.StandardJdkRuleParserTest.runtime.log.txt: -------------------------------------------------------------------------------- 1 | [TRACE] javax.script.ScriptException: javax.script.ScriptException: java.lang.IllegalArgumentException: permission denied! runtime.getBean only support com.itangcent.* 2 | Caused by: javax.script.ScriptException: java.lang.IllegalArgumentException: permission denied! runtime.getBean only support com.itangcent.* 3 | Caused by: java.lang.IllegalArgumentException: permission denied! runtime.getBean only support com.itangcent.* 4 | [TRACE] javax.script.ScriptException: javax.script.ScriptException: java.lang.IllegalArgumentException: class com.itangcent.Unknown not be found 5 | Caused by: javax.script.ScriptException: java.lang.IllegalArgumentException: class com.itangcent.Unknown not be found 6 | Caused by: java.lang.IllegalArgumentException: class com.itangcent.Unknown not be found 7 | [INFO] log in async -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.utils.ContextualPsiClassHelperTest.CachedContextualPsiClassHelperTest.1.txt: -------------------------------------------------------------------------------- 1 | [INFO] before class:com.itangcent.model.UserInfo 2 | [INFO] before field:com.itangcent.model.UserInfo#id 3 | [INFO] after field:com.itangcent.model.UserInfo#id 4 | [INFO] before field:com.itangcent.model.UserInfo#type 5 | [INFO] after field:com.itangcent.model.UserInfo#type 6 | [INFO] before field:com.itangcent.model.UserInfo#name 7 | [INFO] after field:com.itangcent.model.UserInfo#name 8 | [INFO] before field:com.itangcent.model.UserInfo#age 9 | [INFO] after field:com.itangcent.model.UserInfo#age 10 | [INFO] before field:com.itangcent.model.UserInfo#sex 11 | [INFO] after field:com.itangcent.model.UserInfo#sex 12 | [INFO] before field:com.itangcent.model.UserInfo#birthDay 13 | [INFO] after field:com.itangcent.model.UserInfo#birthDay 14 | [INFO] before field:com.itangcent.model.UserInfo#regtime 15 | [INFO] after field:com.itangcent.model.UserInfo#regtime 16 | [INFO] after class:com.itangcent.model.UserInfo 17 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.utils.ContextualPsiClassHelperTest.CachedContextualPsiClassHelperTest.2.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangcent/easy-api/877cc45f6aa57cecdfd569b957e7caa1f31891f9/idea-plugin/src/test/resources/result/com.itangcent.idea.utils.ContextualPsiClassHelperTest.CachedContextualPsiClassHelperTest.2.txt -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.utils.ContextualPsiClassHelperTest.NoCachedContextualPsiClassHelperTest.1.txt: -------------------------------------------------------------------------------- 1 | [INFO] before class:com.itangcent.model.UserInfo 2 | [INFO] before field:com.itangcent.model.UserInfo#id 3 | [INFO] after field:com.itangcent.model.UserInfo#id 4 | [INFO] before field:com.itangcent.model.UserInfo#type 5 | [INFO] after field:com.itangcent.model.UserInfo#type 6 | [INFO] before field:com.itangcent.model.UserInfo#name 7 | [INFO] after field:com.itangcent.model.UserInfo#name 8 | [INFO] before field:com.itangcent.model.UserInfo#age 9 | [INFO] after field:com.itangcent.model.UserInfo#age 10 | [INFO] before field:com.itangcent.model.UserInfo#sex 11 | [INFO] after field:com.itangcent.model.UserInfo#sex 12 | [INFO] before field:com.itangcent.model.UserInfo#birthDay 13 | [INFO] after field:com.itangcent.model.UserInfo#birthDay 14 | [INFO] before field:com.itangcent.model.UserInfo#regtime 15 | [INFO] after field:com.itangcent.model.UserInfo#regtime 16 | [INFO] after class:com.itangcent.model.UserInfo 17 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.idea.utils.ContextualPsiClassHelperTest.NoCachedContextualPsiClassHelperTest.2.txt: -------------------------------------------------------------------------------- 1 | [INFO] before class:com.itangcent.model.UserInfo 2 | [INFO] before field:com.itangcent.model.UserInfo#id 3 | [INFO] after field:com.itangcent.model.UserInfo#id 4 | [INFO] before field:com.itangcent.model.UserInfo#type 5 | [INFO] after field:com.itangcent.model.UserInfo#type 6 | [INFO] before field:com.itangcent.model.UserInfo#name 7 | [INFO] after field:com.itangcent.model.UserInfo#name 8 | [INFO] before field:com.itangcent.model.UserInfo#age 9 | [INFO] after field:com.itangcent.model.UserInfo#age 10 | [INFO] before field:com.itangcent.model.UserInfo#sex 11 | [INFO] after field:com.itangcent.model.UserInfo#sex 12 | [INFO] before field:com.itangcent.model.UserInfo#birthDay 13 | [INFO] after field:com.itangcent.model.UserInfo#birthDay 14 | [INFO] before field:com.itangcent.model.UserInfo#regtime 15 | [INFO] after field:com.itangcent.model.UserInfo#regtime 16 | [INFO] after class:com.itangcent.model.UserInfo 17 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.test.ResultLoaderTest.sub.txt: -------------------------------------------------------------------------------- 1 | 123456789 -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/result/com.itangcent.test.ResultLoaderTest.txt: -------------------------------------------------------------------------------- 1 | asdfghjkl -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/validation/Default.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bean Validation API 3 | * 4 | * License: Apache License, Version 2.0 5 | * See the license.txt file in the root directory or . 6 | */ 7 | package javax.validation.groups; 8 | 9 | /** 10 | * Default Bean Validation group. 11 | *

12 | * Unless a list of groups is explicitly defined: 13 | *

    14 | *
  • constraints belong to the {@code Default} group
  • 15 | *
  • validation applies to the {@code Default} group
  • 16 | *
17 | * Most structural constraints should belong to the default group. 18 | * 19 | * @author Emmanuel Bernard 20 | */ 21 | public interface Default { 22 | } 23 | -------------------------------------------------------------------------------- /idea-plugin/src/test/resources/validation/Validated.java: -------------------------------------------------------------------------------- 1 | // 2 | // Source code recreated from a .class file by IntelliJ IDEA 3 | // (powered by FernFlower decompiler) 4 | // 5 | 6 | package org.springframework.validation.annotation; 7 | 8 | import java.lang.annotation.Documented; 9 | import java.lang.annotation.ElementType; 10 | import java.lang.annotation.Retention; 11 | import java.lang.annotation.RetentionPolicy; 12 | import java.lang.annotation.Target; 13 | 14 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Documented 17 | public @interface Validated { 18 | Class[] value() default {}; 19 | } 20 | -------------------------------------------------------------------------------- /plugin-script/build_plugin.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | 4 | SOURCE="$0" 5 | while [[ -h "$SOURCE" ]]; do # resolve $SOURCE until the file is no longer a symlink 6 | scriptDir="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 7 | SOURCE="$(readlink "$SOURCE")" 8 | [[ ${SOURCE} != /* ]] && SOURCE="$scriptDir/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located 9 | done 10 | scriptDir="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 11 | basedir=${scriptDir%/*} 12 | echo "baseDir:"${basedir} 13 | 14 | cd ${basedir}/idea-plugin 15 | ../gradlew clean buildPlugin --stacktrace 16 | -------------------------------------------------------------------------------- /plugin-script/package_plugin.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | 4 | SOURCE="$0" 5 | while [[ -h "$SOURCE" ]]; do # resolve $SOURCE until the file is no longer a symlink 6 | scriptDir="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 7 | SOURCE="$(readlink "$SOURCE")" 8 | [[ ${SOURCE} != /* ]] && SOURCE="$scriptDir/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located 9 | done 10 | scriptDir="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 11 | basedir=${scriptDir%/*} 12 | echo "baseDir:"${basedir} 13 | 14 | cd ${basedir}/idea-plugin 15 | ../gradlew clean buildPlugin -x test --stacktrace 16 | 17 | version=`cat ${basedir}/gradle.properties | grep -Eo -m1 '[0-9][0-9.]+(-rc)?'` 18 | echo "version:"${version} 19 | 20 | 21 | if [[ ! -d "$basedir/plugin" ]];then 22 | mkdir ${basedir}/plugin 23 | fi 24 | mv ${basedir}/idea-plugin/build/distributions/*.zip ${basedir}/plugin/easy-api-${version}.zip -------------------------------------------------------------------------------- /plugin-script/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | 4 | SOURCE="$0" 5 | while [[ -h "$SOURCE" ]]; do # resolve $SOURCE until the file is no longer a symlink 6 | scriptDir="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 7 | SOURCE="$(readlink "$SOURCE")" 8 | [[ ${SOURCE} != /* ]] && SOURCE="$scriptDir/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located 9 | done 10 | scriptDir="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 11 | basedir=${scriptDir%/*} 12 | echo "baseDir:"${basedir} 13 | 14 | cd ${basedir} 15 | 16 | ./gradlew clean test --stacktrace 17 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "easy-api" 2 | include(":common-api", ":idea-plugin") 3 | 4 | -------------------------------------------------------------------------------- /third/dubbo.config: -------------------------------------------------------------------------------- 1 | generic.class.has.api=groovy:it.name().endsWith("Client") 2 | generic.path=#path 3 | generic.path[groovy:it.contextType()=="class"]=groovy:``` 4 | def name =it.name().replace('.','/') 5 | def index = name.lastIndexOf('/') 6 | "/"+tool.camel2Underline(name[0..index]+tool.uncapitalize(name[index+1..-1])) 7 | ``` 8 | generic.path[groovy:it.contextType()=="method"]=groovy:it.name() 9 | generic.http.method[groovy:it.contextType()=="method"]=groovy:``` 10 | (it.argCnt()==0||it.args().every{it.type().isNormalType()})?"GET":null 11 | ``` 12 | generic.http.method=#method 13 | generic.http.method[#post]=POST 14 | generic.http.method[#POST]=POST 15 | generic.http.method[#get]=GET 16 | generic.http.method[#GET]=GET 17 | #use POST by default 18 | generic.http.method=POST 19 | #always true 20 | generic.method.has.api=true 21 | 22 | #Indicating a method parameter should be bound to the body of the web request. 23 | generic.param.as.json.body=groovy:``` 24 | if(it.type().isNormalType()){ 25 | return false 26 | } 27 | if(it.method().hasDoc("GET")||it.method().hasDoc("get")){ 28 | return false 29 | } 30 | def method = it.method().doc("method") 31 | if(method=="GET"||method=="get"){ 32 | return false 33 | } 34 | return true 35 | ``` 36 | 37 | generic.param.as.form.body=false -------------------------------------------------------------------------------- /third/javax.validation.config: -------------------------------------------------------------------------------- 1 | # rules for javax.validation 2 | 3 | #Support for javax.validation annotations 4 | param.required=@javax.validation.constraints.NotBlank 5 | field.required=@javax.validation.constraints.NotBlank 6 | param.required=@javax.validation.constraints.NotNull 7 | field.required=@javax.validation.constraints.NotNull 8 | param.required=@javax.validation.constraints.NotEmpty 9 | field.required=@javax.validation.constraints.NotEmpty 10 | 11 | # AssertTrue|AssertFalse 12 | field.demo[@javax.validation.constraints.AssertFalse]=false 13 | field.demo[@javax.validation.constraints.AssertTrue]=true -------------------------------------------------------------------------------- /third/swagger.config: -------------------------------------------------------------------------------- 1 | # swagger 2 | 3 | # ApiParam 4 | param.doc=@io.swagger.annotations.ApiParam#value 5 | param.default.value=@io.swagger.annotations.ApiParam#defaultValue 6 | param.required=@io.swagger.annotations.ApiParam#required 7 | param.ignore=@io.swagger.annotations.ApiParam#hidden 8 | 9 | # Api 10 | class.doc=@io.swagger.annotations.Api#value 11 | class.doc=@io.swagger.annotations.Api#tags 12 | ignore=@io.swagger.annotations.Api#hidden 13 | 14 | # ApiModel 15 | class.doc=@io.swagger.annotations.ApiModel#value 16 | class.doc=@io.swagger.annotations.ApiModel#description 17 | 18 | # ApiModelProperty 19 | json.rule.field.name=@io.swagger.annotations.ApiModelProperty#name 20 | field.ignore=@io.swagger.annotations.ApiModelProperty#hidden 21 | field.doc=@io.swagger.annotations.ApiModelProperty#value 22 | field.doc=@io.swagger.annotations.ApiModelProperty#notes 23 | field.required=@io.swagger.annotations.ApiModelProperty#required 24 | 25 | # ApiOperation 26 | method.doc=@io.swagger.annotations.ApiOperation#value 27 | api.tag=@io.swagger.annotations.ApiOperation#tags --------------------------------------------------------------------------------