├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ └── jekyll-gh-pages.yml ├── .gitignore ├── .vscode ├── launch.json ├── setting.json.template └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE.txt ├── README.md ├── client ├── JSDebugger │ ├── jsDebugConfigProvider.ts │ ├── jsDebugManager.ts │ ├── mlDebug.ts │ └── mlRuntime.ts ├── XQDebugger │ ├── xqyDebug.ts │ ├── xqyDebugConfigProvider.ts │ ├── xqyDebugManager.ts │ └── xqyRuntime.ts ├── clientFactory.ts ├── clientResponseProvider.ts ├── configurationManager.ts ├── editorQueryEvaluator.ts ├── extension.ts ├── marklogic-types.d.ts ├── marklogicClient.ts ├── marklogicDebugStatus.ts ├── marklogicServerStatus.ts ├── marklogicTdeValidateClient.ts ├── marklogicUnitTestClient.ts ├── mlxprsErrorBuilder.ts ├── mlxprsErrorReporter.ts ├── mlxprsStatus.ts ├── mlxprsWebViewProvider.ts ├── moduleContentGetter.ts ├── sparqlQueryHelper.ts ├── test │ ├── integration │ │ ├── Issue69.test.ts │ │ ├── Issue70.test.ts │ │ ├── connectAndDisconnect.test.ts │ │ ├── evalFailures.test.ts │ │ ├── index.ts │ │ ├── integration.env │ │ ├── jsScripts │ │ │ ├── MarkLogic │ │ │ │ └── test │ │ │ │ │ ├── invoke1.xqy │ │ │ │ │ ├── jsInvoke-1.sjs │ │ │ │ │ ├── jsInvoke-2.sjs │ │ │ │ │ ├── lib1.sjs │ │ │ │ │ ├── lib2.sjs │ │ │ │ │ ├── test.sjs │ │ │ │ │ └── xqyInvoke-1.xqy │ │ │ ├── eval1.sjs │ │ │ ├── eval2.sjs │ │ │ ├── eval3.sjs │ │ │ ├── helloWorld.sjs │ │ │ ├── invoke1.sjs │ │ │ ├── invoke2.sjs │ │ │ └── nestedInvoke1.sjs │ │ ├── markLogicIntegrationTestHelper.ts │ │ ├── marklogicClient.test.ts │ │ ├── marklogicTdeValidationTest.test.ts │ │ ├── marklogicUnitTest.test.ts │ │ ├── sjsAdapter.test.ts │ │ ├── sjsAdapterBasic.test.ts │ │ ├── sjsAdapterLaunchFailures.test.ts │ │ ├── sslFailures.test.ts │ │ ├── xqyAdapter.test.ts │ │ └── xqyScripts │ │ │ └── factorial.xqy │ ├── runIntegrationTest.ts │ ├── runTest.ts │ └── suite │ │ ├── client.test.ts │ │ ├── defaultDb.test.ts │ │ ├── dummyGlobalState.ts │ │ ├── index.ts │ │ ├── rowsQuery.test.ts │ │ ├── testOverrideQuery.ts │ │ ├── testXqyDebugMessages.ts │ │ └── xqyRuntime.test.ts ├── vscModuleContentProvider.ts ├── vscQueryParameterTools.ts ├── vscodeClientFactory.ts └── xmlFormatting │ ├── Formatting.ts │ ├── LICENSE │ ├── RangeUtil.ts │ └── XmlFormatter.ts ├── docs ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── _config.yml ├── assets │ ├── Progress_PrimarySymbol.svg │ └── attach_screenshot.png ├── debugging-support │ ├── debugging-support.md │ ├── localModules.md │ └── remoteRequests.md ├── development-support │ ├── development-support.md │ ├── tde-templates.md │ └── viewModules.md ├── favicon.ico ├── index.md ├── installationAndConfiguration.md ├── query-and-script-support │ ├── ExecutingGraphQlQueries.md │ ├── ExecutingOpticQueries.md │ ├── ExecutingSparqlQueries.md │ ├── ExecutingSqlQueries.md │ ├── evaluatingModules.md │ └── query-and-script-support.md ├── serverStatusView.md └── testing-support │ ├── runningMarkLogicUnitTests.md │ └── testing-support.md ├── images ├── ProgressMarkLogic_PrimaryLogo_StackedAlternate.png └── attach_screenshot.png ├── media └── Progress_PrimarySymbol.svg ├── package-lock.json ├── package.json ├── server ├── completionTypes.ts ├── completionsSjs.ts ├── completionsXqy.ts ├── etc │ └── marklogic-hint-docs.json ├── package-lock.json ├── package.json ├── server.ts ├── test │ ├── runTest.ts │ ├── suite │ │ ├── index.ts │ │ └── server.test.ts │ └── tsconfig.json ├── tsconfig.json └── webpack.config.js ├── shared.webpack.config.js ├── snippets └── snippets.json ├── syntaxes └── xquery-ml.tmLanguage ├── test-app ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .vscode │ ├── launch.json │ └── settings.json ├── build.gradle ├── docker-compose.yaml ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ ├── main │ ├── ml-bad-schemas │ │ ├── invalid-authors-TDE.json │ │ ├── invalid-json-TDE.json │ │ ├── invalid-publications-TDE.xml │ │ └── invalid-xml-TDE.xml │ ├── ml-config │ │ ├── databases │ │ │ ├── content-database.json │ │ │ └── schemas-database.json │ │ ├── security │ │ │ └── certificate-templates │ │ │ │ └── test-app-ssl-template.xml │ │ └── servers │ │ │ ├── NoSsl-server.json │ │ │ ├── manage-basic.json │ │ │ ├── manage-ssl-server.json │ │ │ ├── rest-api-server.json │ │ │ ├── ssl-server.json │ │ │ └── test-rest-api-server.json │ ├── ml-data │ │ ├── a.json │ │ ├── citations.xml │ │ ├── collections.properties │ │ └── extraCitations.xml │ ├── ml-modules │ │ └── root │ │ │ ├── graphql │ │ │ └── authors.json │ │ │ ├── javascript │ │ │ ├── callOptic.sjs │ │ │ ├── launch.sjs │ │ │ ├── library.sjs │ │ │ ├── random.js │ │ │ ├── testJs.js │ │ │ ├── testModule.mjs │ │ │ └── testSjs.sjs │ │ │ ├── lib │ │ │ └── factorial.sjs │ │ │ ├── optic │ │ │ ├── dslQuery.js │ │ │ └── query.json │ │ │ ├── sparql │ │ │ └── some.sparql │ │ │ ├── sql │ │ │ └── authors.sql │ │ │ └── xquery │ │ │ ├── callOptic.xqy │ │ │ ├── eval.xqy │ │ │ ├── launch.xqy │ │ │ ├── library.xqy │ │ │ ├── longTest.xqy │ │ │ ├── overrideTest.xqy │ │ │ └── testXqy.xqy │ └── ml-schemas │ │ └── tde │ │ ├── authors-TDE.json │ │ ├── authors-local-data-TDE.json │ │ ├── no-var-authors-TDE.json │ │ ├── no-var-publications-TDE.xml │ │ ├── publications-TDE.xml │ │ ├── publications-local-data-TDE.xml │ │ └── small-authors-TDE.json │ └── test │ ├── ml-modules │ └── root │ │ └── test │ │ └── suites │ │ ├── SampleJavaScriptTestSuite │ │ ├── sample-failing-jstest.sjs │ │ ├── sample-jstest.sjs │ │ └── setup.sjs │ │ └── SampleXQueryTestSuite │ │ ├── sample-tests.xqy │ │ ├── setup.xqy │ │ ├── suite-setup.xqy │ │ ├── suite-teardown.xqy │ │ └── teardown.xqy │ └── resources │ └── localCitationsData.xml ├── tsconfig.json ├── webpack.config.js ├── webpack.test.js └── xquery-ml.configuration.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.js] 13 | indent_size = 4 14 | 15 | [*.json] 16 | indent_size = 4 17 | 18 | [*.ts] 19 | indent_size = 4 20 | 21 | [*.md] 22 | trim_trailing_whitespace = false 23 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | server/dist -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "extends": "plugin:@typescript-eslint/recommended", 7 | "globals": { 8 | "Atomics": "readonly", 9 | "SharedArrayBuffer": "readonly" 10 | }, 11 | "parser": "@typescript-eslint/parser", 12 | "plugins": [ 13 | "@typescript-eslint" 14 | ], 15 | "parserOptions": { 16 | "ecmaVersion": 2018, 17 | "sourceType": "module" 18 | }, 19 | "overrides": [ 20 | { 21 | "files": "**/*.ts", 22 | "excludedFiles": [ 23 | "dist/**/*.js", 24 | "out/**/*.js" 25 | ] 26 | } 27 | ], 28 | "rules": { 29 | "indent": [ 30 | "error", 31 | 4 32 | ], 33 | "linebreak-style": [ 34 | "error", 35 | "unix" 36 | ], 37 | "quotes": [ 38 | "error", 39 | "single" 40 | ], 41 | "semi": [ 42 | "error", 43 | "always" 44 | ], 45 | "arrow-spacing": [ 46 | "error", 47 | { 48 | "before": true, 49 | "after": true 50 | } 51 | ], 52 | "space-before-blocks": [ 53 | "error", 54 | "always" 55 | ], 56 | "space-before-function-paren": [ 57 | "error", 58 | { 59 | "named": "never", 60 | "asyncArrow": "always" 61 | } 62 | ], 63 | "space-in-parens": [ 64 | "error", 65 | "never" 66 | ], 67 | "object-curly-spacing": [ 68 | "error", 69 | "always" 70 | ], 71 | "keyword-spacing": [ 72 | "error", 73 | { 74 | "before": true, 75 | "after": true 76 | } 77 | ], 78 | "comma-spacing": [ 79 | "error", 80 | { 81 | "before": false, 82 | "after": true 83 | } 84 | ], 85 | "key-spacing": [ 86 | "error", 87 | { 88 | "beforeColon": false, 89 | "afterColon": true 90 | } 91 | ], 92 | "space-infix-ops": [ 93 | "error" 94 | ], 95 | "no-var": "error", 96 | "array-bracket-spacing": "error", 97 | "block-spacing": "error", 98 | "brace-style": [ 99 | "error", 100 | "1tbs", 101 | { 102 | "allowSingleLine": false 103 | } 104 | ], 105 | "curly": [ 106 | "error", 107 | "multi-line" 108 | ], 109 | "func-call-spacing": "error", 110 | "no-trailing-spaces": "error", 111 | "no-console": [ 112 | "error", 113 | { 114 | "allow": [ 115 | "warn", 116 | "error", 117 | "debug" 118 | ] 119 | } 120 | ], 121 | "eqeqeq": "error", 122 | "@typescript-eslint/no-explicit-any": "warn", 123 | "@typescript-eslint/no-unused-vars": "warn" 124 | } 125 | } -------------------------------------------------------------------------------- /.github/workflows/jekyll-gh-pages.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages 2 | name: Deploy Jekyll with GitHub Pages dependencies preinstalled 3 | 4 | on: 5 | # Runs on pushes targeting the default branch. 6 | push: 7 | branches: ["master"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow one concurrent deployment 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | # Build job 25 | build: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v3 30 | - name: Setup Pages 31 | uses: actions/configure-pages@v3 32 | - name: Build with Jekyll 33 | uses: actions/jekyll-build-pages@v1 34 | with: 35 | source: ./docs/ 36 | destination: ./_site 37 | - name: Upload artifact 38 | uses: actions/upload-pages-artifact@v1 39 | 40 | # Deployment job 41 | deploy: 42 | environment: 43 | name: github-pages 44 | url: ${{ steps.deployment.outputs.page_url }} 45 | runs-on: ubuntu-latest 46 | needs: build 47 | steps: 48 | - name: Deploy to GitHub Pages 49 | id: deployment 50 | uses: actions/deploy-pages@v1 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | server/*.js 4 | server/node_modules 5 | *.vsix 6 | dist 7 | .DS_Store 8 | .vscode/settings.json 9 | .vscode-test 10 | .gradle 11 | gradle-local.properties 12 | results/ 13 | coverage/ 14 | test-app/.gradle 15 | test-app/build 16 | test-app/docker 17 | 18 | test-app/src/main/ml-modules/root/MarkLogic 19 | -------------------------------------------------------------------------------- /.vscode/setting.json.template: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | "editor.formatOnSave": true, 10 | "[typescript]": { 11 | "editor.defaultFormatter": "vscode.typescript-language-features" 12 | }, 13 | "marklogic.host": "localhost", 14 | "marklogic.username": "admin", 15 | "marklogic.password": "XXXX", 16 | "marklogic.port": 8055, 17 | "marklogic.documentsDb": "mlxprs-test-content", 18 | "marklogic.modulesDb": "mlxprs-test-modules", 19 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | // A task runner that calls a custom npm script that compiles the extension. 9 | { 10 | "version": "2.0.0", 11 | "tasks": [ 12 | { 13 | "type": "npm", 14 | "script": "compile", 15 | "problemMatcher": "$tsc-watch", 16 | "isBackground": true, 17 | "presentation": { 18 | "reveal": "silent" 19 | }, 20 | "group": "build" 21 | }, 22 | { 23 | "type": "npm", 24 | "script": "watch", 25 | "problemMatcher": [ 26 | "$ts-webpack-watch" 27 | ], 28 | "isBackground": true, 29 | "presentation": { 30 | "echo": true, 31 | "reveal": "silent", 32 | "focus": false, 33 | "panel": "shared", 34 | "showReuseMessage": true, 35 | "clear": false 36 | }, 37 | "group": "build" 38 | }, 39 | { 40 | "type": "npm", 41 | "script": "pretest", 42 | "problemMatcher": "$tsc-watch", 43 | "isBackground": true, 44 | "presentation": { 45 | "reveal": "never" 46 | }, 47 | "group": "build" 48 | }, 49 | { 50 | "type": "npm", 51 | "script": "predebug", 52 | "problemMatcher": "$tsc-watch", 53 | "isBackground": true, 54 | "presentation": { 55 | "reveal": "never" 56 | }, 57 | "group": "build" 58 | } 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | typings/** 3 | out/test/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | vsc-extension-quickstart.md 10 | webpack.config.js 11 | **/node_modules 12 | node_modules 13 | server/test/** 14 | server/out/** 15 | client/test/** 16 | client/out/** 17 | **/*.ts 18 | **/*webpack.config.js 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![](https://vsmarketplacebadges.dev/version/mlxprs.mlxprs.png)](https://marketplace.visualstudio.com/items?itemName=mlxprs.mlxprs) 2 | [![](https://vsmarketplacebadges.dev/installs-short/mlxprs.mlxprs.png)](https://marketplace.visualstudio.com/items?itemName=mlxprs.mlxprs) 3 | [![](https://vsmarketplacebadges.dev/rating-short/mlxprs.mlxprs.png)](https://marketplace.visualstudio.com/items?itemName=mlxprs.mlxprs) 4 | 5 | # MLXPRS: MarkLogic Extension for Visual Studio Code 6 | 7 | _Develop, run, and debug code for MarkLogic in the popular VS Code IDE_ 8 | 9 | [Visual Studio Code](https://code.visualstudio.com), also known as VS Code, is a free, cross-platform code editor and development tool from Microsoft. [**MLXPRS**](https://marketplace.visualstudio.com/items?itemName=mlxprs.mlxprs) is a free, open-source extension for VS Code that increases the productivity of developers creating applications on MarkLogic. 10 | 11 | ## Features 12 | 13 | * Syntax highlighting and IntelliSense for MarkLogic Server-Side JavaScript and XQuery 14 | * Interactive debugging of JavaScript and XQuery running in MarkLogic, including attaching to in-flight requests and inspecting live variables 15 | * Real-time query evaluation of JavaScript, XQuery, SQL, SPARQL, Optic, and GraphQL against a MarkLogic instance 16 | * View modules (read-only) in the editor 17 | * Run [marklogic-unit-test module](https://github.com/marklogic-community/marklogic-unit-test) 18 | * Validate TDE templates and test the templates with node extraction 19 | * View high-level information about the currently connected MarkLogic server 20 | 21 | _JavaScript debugging requires version 2.0.0+ of the MarkLogic extension and [MarkLogic 10.0-4+](https://developer.marklogic.com/products/marklogic-server/10.0)._ 22 | 23 | 24 | ## Getting started 25 | 26 | Install this tool using the VS Code built-in [marketplace](https://marketplace.visualstudio.com/items?itemName=mlxprs.mlxprs). Search “MarkLogic” from the Extension tab of the activity bar. Click “Install” to download and install the extension. 27 | 28 | For more information on installation, configuration and usage, please see [the User Guide](https://marklogic.github.io/mlxprs/). 29 | 30 | ## Credit 31 | 32 | Aside from excellent development and extension support from Visual Studio Code, 33 | 34 | - Portions of Josh Johnson's [vscode-xml](https://github.com/DotJoshJohnson/vscode-xml) project are re-used 35 | for XML formatting. The MIT license and source code are kept in the `client/xmlFormatting` folder of this project. 36 | - Christy Haragan's [marklogic-node-typescript-definitions](https://github.com/christyharagan/ml-typescript-definitions) 37 | made this project possible. 38 | - Paxton Hare's [marklogic-sublime](https://github.com/paxtonhare/MarkLogic-Sublime) 39 | `xquery-ml.tmLanguage` code is used for XQuery-ML syntax and snippets, and the MarkLogic Sublime project inspired this one. 40 | -------------------------------------------------------------------------------- /client/configurationManager.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as vscode from 'vscode'; 18 | 19 | export interface MarklogicConfigurationSettings { 20 | host?: string; 21 | port?: string; 22 | restBasePath?: string; 23 | managePort?: string; 24 | manageBasePath?: string; 25 | testPort?: string; 26 | testBasePath?: string; 27 | adminPort?: string; 28 | adminBasePath?: string; 29 | username?: string; 30 | password?: string; 31 | documentsDb?: string; 32 | modulesDb?: string; 33 | authType?: string; 34 | apiKey?: string; 35 | accessTokenDuration?: string; 36 | ssl?: string; 37 | pathToCa?: string; 38 | rejectUnauthorized?: string; 39 | } 40 | 41 | export class ConfigurationManager { 42 | 43 | private static vscodeConfiguration: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('marklogic'); 44 | private static overrides: MarklogicConfigurationSettings = {}; 45 | 46 | static setOverride(key: string, val: unknown): void { 47 | ConfigurationManager.overrides[key] = val; 48 | } 49 | 50 | static handleUpdateConfigurationEvent(): void { 51 | ConfigurationManager.vscodeConfiguration = vscode.workspace.getConfiguration('marklogic'); 52 | } 53 | 54 | static getConfigValue(key: string): unknown { 55 | if (ConfigurationManager.overrides[key]) { 56 | return ConfigurationManager.overrides[key]; 57 | } else { 58 | return ConfigurationManager.vscodeConfiguration.get(key); 59 | } 60 | } 61 | 62 | static getHost(): string { 63 | return ConfigurationManager.getConfigValue('host') as string; 64 | } 65 | 66 | static getPort(): number { 67 | return Number(ConfigurationManager.getConfigValue('port')); 68 | } 69 | 70 | static getRestBasePath(): string { 71 | return ConfigurationManager.getConfigValue('restBasePath') as string; 72 | } 73 | 74 | static getManagePort(): number { 75 | return Number(ConfigurationManager.getConfigValue('managePort')) as number; 76 | } 77 | 78 | static getManageBasePath(): string { 79 | return ConfigurationManager.getConfigValue('manageBasePath') as string; 80 | } 81 | 82 | static getTestPort(): number { 83 | return Number(ConfigurationManager.getConfigValue('testPort')) as number; 84 | } 85 | 86 | static getTestBasePath(): string { 87 | return ConfigurationManager.getConfigValue('testBasePath') as string; 88 | } 89 | 90 | static getAdminPort(): number { 91 | return Number(ConfigurationManager.getConfigValue('adminPort')) as number; 92 | } 93 | 94 | static getAdminBasePath(): string { 95 | return ConfigurationManager.getConfigValue('testAdminPath') as string; 96 | } 97 | 98 | static getUsername(): string { 99 | return ConfigurationManager.getConfigValue('username') as string; 100 | } 101 | 102 | static getPassword(): string { 103 | return ConfigurationManager.getConfigValue('password') as string; 104 | } 105 | 106 | static getDocumentsDb(): string { 107 | return ConfigurationManager.getConfigValue('documentsDb') as string; 108 | } 109 | 110 | static getModulesDb(): string { 111 | return ConfigurationManager.getConfigValue('modulesDb') as string; 112 | } 113 | 114 | static getAuthType(): string { 115 | return ConfigurationManager.getConfigValue('authType') as string; 116 | } 117 | 118 | static getApiKey(): string { 119 | return ConfigurationManager.getConfigValue('apiKey') as string; 120 | } 121 | 122 | static getAccessTokenDuration(): number { 123 | return ConfigurationManager.getConfigValue('accessTokenDuration') as number; 124 | } 125 | 126 | static getSsl(): boolean { 127 | return Boolean(ConfigurationManager.getConfigValue('ssl')) as boolean; 128 | } 129 | 130 | static getPathToCa(): string { 131 | return ConfigurationManager.getConfigValue('pathToCa') as string; 132 | } 133 | 134 | static getRejectUnauthorized(): boolean { 135 | return Boolean(ConfigurationManager.getConfigValue('rejectUnauthorized')) as boolean; 136 | } 137 | } -------------------------------------------------------------------------------- /client/marklogic-types.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | declare module 'marklogic' { 18 | 19 | export interface ResultProvider extends NodeJS.ReadWriteStream { 20 | result(onFulfilled: (value: R) => Promise, onRejected: (error: any) => Promise, onProgress?: (note: any) => any): Promise; 21 | result(onFulfilled: (value: R) => Promise, onRejected?: (error: any) => U, onProgress?: (note: any) => any): Promise; 22 | result(onFulfilled: (value: R) => U, onRejected: (error: any) => Promise, onProgress?: (note: any) => any): Promise; 23 | result(onFulfilled?: (value: R) => U, onRejected?: (error: any) => U, onProgress?: (note: any) => any): Promise; 24 | } 25 | 26 | export type contentType = 'application/json' | 'application/xml' | 'text/html' | 'text/csv' 27 | export type RowsResponseFormat = 'json' | 'xml' | 'csv' 28 | export type RowsQueryType = 'dsl' | 'json' 29 | 30 | // application/trig should be supported according to the documentation 31 | // but there appears to be a bug in the implementation 32 | // so I removed it from package.json as an option 33 | export type SparqlResponseFormat = 'application/sparql-results+json' | 'application/sparql-results+xml' | 'text/html' | 'text/csv' | 34 | 'application/n-triples' | 'application/n-quads' | 'application/rdf+json' | 'application/rdf+xml' | 35 | 'text/turtle' | 'text/n3' | 'application/trig' | 'application/json' 36 | export type SparqlQueryType = 'select' | 'construct' | 'describe' | 'ask' | 'unknown' 37 | 38 | interface Graphs { 39 | sparql: (args: Record) => ResultProvider 40 | } 41 | 42 | export type Item = { 43 | format: string, 44 | datatype: string, 45 | value: any 46 | } 47 | 48 | export type RowsResponse = { 49 | columns: { name: string }[], 50 | rows: object[], 51 | preRequestError: string 52 | } 53 | 54 | export type RowsOptions = { 55 | queryType: RowsQueryType 56 | format: RowsResponseFormat 57 | } 58 | 59 | interface Rows { 60 | graphQL: (actualQuery: object | string) => Promise 61 | query: (actualQuery: object | string, options: RowsOptions) => Promise 62 | } 63 | 64 | export type RequestOptions = { 65 | path: string, 66 | method: string, 67 | headers: object 68 | } 69 | 70 | export type RequestOperation = { 71 | requestBody: string 72 | } 73 | 74 | interface Internal { 75 | sendRequest( 76 | path: string, 77 | requestOptionsCallback?: object, 78 | operationCallback?: object 79 | ): ResultProvider 80 | } 81 | 82 | export interface DatabaseClient { 83 | release: () => void; 84 | xqueryEval: (query: string, variables?: Variables) => ResultProvider 85 | eval: (query: string, variables?: Variables) => ResultProvider 86 | invoke: (path: string, variables?: Variables) => ResultProvider 87 | read: (uri: string) => ResultProvider 88 | graphs: Graphs 89 | rows: Rows 90 | writeCollection: (collection: string, documents: Record[]) => ResultProvider 91 | removeCollection: (collection: string) => ResultProvider 92 | internal: Internal 93 | } 94 | 95 | export interface ConnectionParams { 96 | host: string; 97 | port: number; 98 | basePath?: string; 99 | user: string; 100 | password: string; 101 | database: string; 102 | authType: string; 103 | apiKey: string; 104 | accessTokenDuration: number; 105 | ssl: boolean; 106 | ca: string; 107 | rejectUnauthorized: boolean; 108 | } 109 | 110 | export interface Variables { 111 | [name: string]: number | string | boolean | Array; 112 | } 113 | 114 | export function createDatabaseClient(connectionParams: ConnectionParams): DatabaseClient 115 | } 116 | -------------------------------------------------------------------------------- /client/marklogicDebugStatus.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | import { ClientContext } from './marklogicClient'; 4 | import { buildClientFactoryFromWorkspaceConfig } from './vscodeClientFactory'; 5 | 6 | export class MarkLogicDebugStatusTreeDataProvider implements vscode.TreeDataProvider { 7 | 8 | private _onDidChangeTreeData: vscode.EventEmitter = 9 | new vscode.EventEmitter(); 10 | readonly onDidChangeTreeData: vscode.Event = 11 | this._onDidChangeTreeData.event; 12 | 13 | private dbClientContext: ClientContext; 14 | private managePort: number; 15 | private manageBasePath: string; 16 | private: ClientContext; 17 | 18 | constructor() { 19 | this.configure(); 20 | } 21 | 22 | onConfigurationChanged(event: vscode.ConfigurationChangeEvent) { 23 | if (event.affectsConfiguration('marklogic')) { 24 | this.dbClientContext.databaseClient.release(); 25 | this.configure(); 26 | this.refresh(); 27 | } 28 | } 29 | 30 | private configure() { 31 | this.dbClientContext = 32 | buildClientFactoryFromWorkspaceConfig(vscode.workspace.getConfiguration()) 33 | .newMarklogicManageClient(); 34 | } 35 | 36 | refresh(): void { 37 | this._onDidChangeTreeData.fire(); 38 | } 39 | 40 | // implements 41 | getTreeItem(element: MarkLogicDebugStatus): vscode.TreeItem { 42 | return element; 43 | } 44 | 45 | // implements 46 | getChildren(element?: MarkLogicDebugStatus): Thenable { 47 | if (element) { 48 | if (element.label === 'Debug App Servers') { 49 | return this.buildDebugAppServerEntries(); 50 | } else { 51 | return Promise.resolve([]); 52 | } 53 | } else { 54 | return Promise.resolve(this.buildTopLevelStatusEntries()); 55 | } 56 | } 57 | 58 | private buildTopLevelStatusEntries(): MarkLogicDebugStatus[] { 59 | return [ 60 | new MarkLogicDebugStatus( 61 | 'Debug App Servers', 62 | '', 63 | '', 64 | vscode.TreeItemCollapsibleState.Collapsed, 65 | { 66 | command: 'markLogicDebugStatusTree.refreshEntry', 67 | title: '', 68 | arguments: [] 69 | } 70 | ) 71 | ]; 72 | } 73 | 74 | private async buildDebugAppServerEntries(): Promise { 75 | const connectedServerTreeElementList: MarkLogicDebugStatus[] = []; 76 | return this.dbClientContext.getConnectedServers(null, this.dbClientContext.params.port, this.dbClientContext.params.restBasePath, null) 77 | .then((connectedServers) => { 78 | if (connectedServers.length > 0) { 79 | connectedServers.forEach(serverName => { 80 | connectedServerTreeElementList.push(this.createSimpleTreeLeaf(serverName)); 81 | }); 82 | } else { 83 | connectedServerTreeElementList.push(this.createSimpleTreeLeaf('No Connected Servers')); 84 | } 85 | return connectedServerTreeElementList; 86 | }); 87 | } 88 | 89 | private createSimpleTreeLeaf(label: string) { 90 | return new MarkLogicDebugStatus( 91 | label, 92 | '', 93 | '', 94 | vscode.TreeItemCollapsibleState.None, 95 | null 96 | ); 97 | } 98 | } 99 | 100 | export class MarkLogicDebugStatus extends vscode.TreeItem { 101 | 102 | constructor( 103 | public readonly label: string, 104 | public readonly tooltip: string, 105 | public readonly description: string, 106 | public readonly collapsibleState: vscode.TreeItemCollapsibleState, 107 | public readonly command?: vscode.Command 108 | ) { 109 | super(label, collapsibleState); 110 | this.tooltip = tooltip; 111 | } 112 | 113 | contextValue = 'TODO'; 114 | } -------------------------------------------------------------------------------- /client/marklogicUnitTestClient.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | import path = require('path'); 20 | import { ExtensionContext, TextEditor, workspace } from 'vscode'; 21 | 22 | import { ClientContext, requestMarkLogicUnitTest } from './marklogicClient'; 23 | import { buildClientFactoryFromWorkspaceConfig } from './vscodeClientFactory'; 24 | import { buildMlxprsErrorFromError, MlxprsError } from './mlxprsErrorBuilder'; 25 | import { MlxprsErrorReporter } from './mlxprsErrorReporter'; 26 | import { MlxprsWebViewProvider } from './mlxprsWebViewProvider'; 27 | 28 | export class MarkLogicUnitTestClient { 29 | static mlxprsWebViewProvider: MlxprsWebViewProvider = null; 30 | 31 | public static registerMlxprsResultsViewProvider(mlxprsWebViewProvider: MlxprsWebViewProvider) { 32 | MarkLogicUnitTestClient.mlxprsWebViewProvider = mlxprsWebViewProvider; 33 | } 34 | 35 | private extensionContext: ExtensionContext; 36 | 37 | public constructor(context: ExtensionContext) { 38 | this.extensionContext = context; 39 | } 40 | 41 | public async runTestModule( 42 | editor: TextEditor 43 | ): Promise { 44 | const splitString = `test${path.sep}suites${path.sep}`; 45 | const filePath = editor.document.uri.path; 46 | const splitLocation = filePath.lastIndexOf(splitString) + splitString.length; 47 | if (splitLocation > splitString.length) { 48 | const testPath = filePath.substring(splitLocation); 49 | const lastSlash = testPath.lastIndexOf('/'); 50 | const testSuite = testPath.substring(0, lastSlash); 51 | const testFile = testPath.substring(lastSlash + 1); 52 | 53 | const dbClientContext: ClientContext = 54 | buildClientFactoryFromWorkspaceConfig(workspace.getConfiguration()) 55 | .newMarklogicRestClient(); 56 | requestMarkLogicUnitTest(dbClientContext, testSuite, testFile) 57 | .result((testResults: string) => { 58 | const testResultsHtml = MlxprsWebViewProvider.convertXmlResponseToHtml(testResults); 59 | MarkLogicUnitTestClient.mlxprsWebViewProvider.updateViewContent(testResultsHtml); 60 | return null; 61 | }) 62 | .catch(error => { 63 | const mlxprsError: MlxprsError = buildMlxprsErrorFromError(error, `Unable to run the test module: ${error['code']}`); 64 | MlxprsErrorReporter.reportError(mlxprsError); 65 | return null; 66 | }); 67 | } else { 68 | const errorMessage = 'Unable to run test; please ensure the file is a marklogic-unit-test module located in a test suite directory'; 69 | const pathError = new Error(errorMessage); 70 | const mlxprsError: MlxprsError = buildMlxprsErrorFromError(pathError, errorMessage); 71 | MlxprsErrorReporter.reportError(mlxprsError); 72 | return null; 73 | } 74 | return null; 75 | } 76 | } -------------------------------------------------------------------------------- /client/mlxprsErrorBuilder.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export interface MlxprsError { 18 | popupMessage: string; 19 | reportedMessage: string; 20 | stack: string; 21 | code?: string 22 | } 23 | 24 | export function buildMlxprsErrorFromError(error: Error, popupMessageBase: string): MlxprsError { 25 | const mlxprsError: MlxprsError = { 26 | reportedMessage: `${popupMessageBase}`, 27 | stack: 'Unable to find the stack trace in the error object', 28 | popupMessage: `${popupMessageBase}` 29 | }; 30 | if (error['reason']) { 31 | mlxprsError.popupMessage = `${popupMessageBase}:${error['reason']}`; 32 | } 33 | if (error.message) { 34 | mlxprsError.reportedMessage = error.message; 35 | mlxprsError.popupMessage = `${popupMessageBase}:${error.message}`; 36 | } 37 | if (error.stack) { 38 | mlxprsError.stack = error.stack; 39 | } 40 | if (error['code']) { 41 | mlxprsError.code = error['code']; 42 | } 43 | if (error['statusCode']) { 44 | mlxprsError.code = error['statusCode']; 45 | } 46 | if (error['body']) { 47 | if (error['body']['errorResponse']) { 48 | mlxprsError.reportedMessage = error['body']['errorResponse']['message']; 49 | mlxprsError.code = error['body']['errorResponse']['messageCode']; 50 | if (error['body']['errorResponse']['status']) { 51 | mlxprsError.popupMessage = `${popupMessageBase}:${error['body']['errorResponse']['status']}`; 52 | } 53 | if (error['body']['errorResponse']['message']) { 54 | mlxprsError.popupMessage = `${popupMessageBase}:${error['body']['errorResponse']['message']}`; 55 | } 56 | if (error['body']['errorResponse']['messageCode']) { 57 | mlxprsError.popupMessage = `${popupMessageBase}:${error['body']['errorResponse']['messageCode']}`; 58 | } 59 | } 60 | } 61 | return mlxprsError; 62 | } 63 | -------------------------------------------------------------------------------- /client/mlxprsErrorReporter.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { window } from 'vscode'; 18 | 19 | import { MlxprsError } from './mlxprsErrorBuilder'; 20 | 21 | export class MlxprsErrorReporter { 22 | static mlxprsOutput = window.createOutputChannel('mlxprs'); 23 | 24 | static reportError(mlxprsError: MlxprsError) { 25 | MlxprsErrorReporter.mlxprsOutput.appendLine(`Error Message: ${mlxprsError.reportedMessage}`); 26 | if (mlxprsError.code) { 27 | MlxprsErrorReporter.mlxprsOutput.appendLine(`Error Code: ${mlxprsError.code}`); 28 | } 29 | MlxprsErrorReporter.mlxprsOutput.appendLine(`Stack: ${mlxprsError.stack}`); 30 | MlxprsErrorReporter.mlxprsOutput.show(); 31 | window.showErrorMessage(mlxprsError.popupMessage); 32 | } 33 | } -------------------------------------------------------------------------------- /client/mlxprsStatus.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as vscode from 'vscode'; 18 | 19 | import { ClientContext } from './marklogicClient'; 20 | import { buildClientFactoryFromWorkspaceConfig } from './vscodeClientFactory'; 21 | 22 | export class MlxprsStatus { 23 | private dbClientContext: ClientContext; 24 | private statusBarItem: vscode.StatusBarItem; 25 | private commandId = 'mlxprs.showConnectedServers'; 26 | private command: vscode.Disposable; 27 | private connectedServers = null; 28 | private managePort: number; 29 | private manageBasePath: string; 30 | 31 | constructor() { 32 | this.configure(); 33 | 34 | this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100); 35 | this.command = vscode.commands.registerCommand(this.commandId, () => { 36 | this.handleStatusBarCommand(); 37 | }); 38 | this.statusBarItem.command = this.commandId; 39 | } 40 | 41 | onConfigurationChanged(event: vscode.ConfigurationChangeEvent) { 42 | if (event.affectsConfiguration('marklogic')) { 43 | if (this.dbClientContext.databaseClient) { 44 | this.dbClientContext.databaseClient.release(); 45 | } 46 | this.configure(); 47 | } 48 | } 49 | 50 | private configure() { 51 | const clientFactory = buildClientFactoryFromWorkspaceConfig(vscode.workspace.getConfiguration()); 52 | this.dbClientContext = clientFactory.newMarklogicRestClient(); 53 | this.managePort = clientFactory.managePort; 54 | this.manageBasePath = clientFactory.manageBasePath; 55 | } 56 | 57 | getCommand(): vscode.Disposable { 58 | return this.command; 59 | } 60 | 61 | getStatusBarItem(): vscode.StatusBarItem { 62 | return this.statusBarItem; 63 | } 64 | 65 | requestUpdate(): void { 66 | this.dbClientContext.getConnectedServers(this, this.managePort, this.manageBasePath, this.updateStatusBarItem); 67 | } 68 | 69 | updateStatusBarItem(connectedServers: string[]): void { 70 | if (connectedServers.length > 0) { 71 | this.connectedServers = connectedServers; 72 | this.statusBarItem.text = 'Server connected'; 73 | } else { 74 | this.connectedServers = null; 75 | this.statusBarItem.text = 'No servers connected'; 76 | } 77 | this.statusBarItem.show(); 78 | } 79 | 80 | handleStatusBarCommand(): void { 81 | if (this.connectedServers) { 82 | vscode.window.showInformationMessage(JSON.stringify(this.connectedServers)); 83 | } else { 84 | vscode.window.showInformationMessage('Use a "MarkLogic: Connect" command to connect to a debug server'); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /client/mlxprsWebViewProvider.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { XMLParser, XMLBuilder } from 'fast-xml-parser'; 18 | import { 19 | CancellationToken, SnippetString, Uri, Webview, WebviewView, 20 | WebviewViewProvider, WebviewViewResolveContext, window 21 | } from 'vscode'; 22 | 23 | export class MlxprsWebViewProvider implements WebviewViewProvider { 24 | 25 | public static readonly viewType = 'mlxprs.ResultsView'; 26 | 27 | private _view?: WebviewView; 28 | private content: string = null; 29 | 30 | constructor( 31 | private readonly _extensionUri: Uri, 32 | ) { } 33 | 34 | public resolveWebviewView( 35 | webviewView: WebviewView, 36 | context: WebviewViewResolveContext, 37 | _token: CancellationToken, 38 | ) { 39 | this._view = webviewView; 40 | 41 | webviewView.webview.options = { 42 | // Allow scripts in the webview 43 | enableScripts: true, 44 | 45 | localResourceRoots: [ 46 | this._extensionUri 47 | ] 48 | }; 49 | if (this.content) { 50 | this.updateViewContent(this.content); 51 | } else { 52 | this.updateViewContent(''); 53 | } 54 | 55 | webviewView.webview.onDidReceiveMessage(data => { 56 | switch (data.type) { 57 | case 'colorSelected': 58 | { 59 | window.activeTextEditor?.insertSnippet(new SnippetString(`#${data.value}`)); 60 | break; 61 | } 62 | } 63 | }); 64 | } 65 | 66 | public updateViewContent(newContent: string) { 67 | this.content = newContent; 68 | if (this._view) { 69 | this._view.webview.html = this.getWebviewContent(this._view.webview, newContent); 70 | } 71 | } 72 | 73 | private getWebviewContent(webview: Webview, content: string) { 74 | return ` 75 | 76 | 77 | 78 | 79 | Example Webview 80 | 81 | 82 | ${content} 83 | 84 | `; 85 | } 86 | 87 | public static convertXmlResponseToHtml(rawXml: string): string { 88 | const options = { 89 | ignoreAttributes: false, 90 | attributeNamePrefix: '@_', 91 | format: true 92 | }; 93 | const parser = new XMLParser(options); 94 | const jObj = parser.parse(rawXml); 95 | const builder = new XMLBuilder(options); 96 | const formattedXml = builder.build(jObj); 97 | 98 | const lineCount = (formattedXml.match(/\n/g) || []).length + 1; 99 | return `'; 100 | } 101 | 102 | public static convertTextResponseToHtml(text: string): string { 103 | return '
' + text + '
'; 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /client/moduleContentGetter.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | import { ClientContext, sendXQuery } from './marklogicClient'; 20 | import { ClientFactory } from './clientFactory'; 21 | 22 | export const listModulesQuery = 'cts:uris()'; 23 | 24 | export class ModuleContentGetter { 25 | private dbClientContext: ClientContext; 26 | 27 | public constructor(dbClientContext: ClientContext) { 28 | const moduleGetterParams: Record = dbClientContext.params; 29 | moduleGetterParams.password = moduleGetterParams.pwd; 30 | this.dbClientContext = 31 | new ClientFactory(moduleGetterParams) 32 | .newMarklogicModulesClient(); 33 | } 34 | 35 | public host(): string { 36 | return this.dbClientContext.params.host; 37 | } 38 | 39 | public port(): number { 40 | return this.dbClientContext.params.port; 41 | } 42 | 43 | public initialize(dbClientContext: ClientContext): void { 44 | this.dbClientContext = dbClientContext; 45 | } 46 | 47 | public async provideTextDocumentContent(modulePath: string): Promise { 48 | return this.dbClientContext.databaseClient.read(modulePath) 49 | .result( 50 | (fulfill: string[]) => { 51 | const moduleContent: string = fulfill[0]; 52 | return moduleContent; 53 | }, 54 | (err) => { 55 | throw err; 56 | }); 57 | } 58 | 59 | public async listModules(): Promise { 60 | return sendXQuery(this.dbClientContext, listModulesQuery) 61 | .result( 62 | (fulfill: Record[]) => { 63 | return fulfill.map(o => { 64 | return o.value; 65 | }); 66 | }, 67 | (err) => { 68 | throw err; 69 | }); 70 | } 71 | 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /client/sparqlQueryHelper.ts: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | import * as ml from 'marklogic' 3 | import { workspace } from 'vscode' 4 | 5 | export function getSparqlQueryForm(query: string): ml.SparqlQueryType { 6 | //TODO: Use the language server for this 7 | const regex = /^(?:[^#]|<.*>)*?(SELECT|CONSTRUCT|ASK|DESCRIBE)/im 8 | const match = query.match(regex) 9 | return (match ? match[1].toLowerCase() : 'unknown') 10 | } 11 | 12 | export function getSparqlResponseType(queryType: ml.SparqlQueryType): ml.SparqlResponseFormat { 13 | switch (queryType) { 14 | case 'select': 15 | { 16 | return workspace.getConfiguration().get('marklogic.sparqlSelectResponseType') as ml.SparqlResponseFormat 17 | } 18 | case 'construct': 19 | case 'describe': 20 | { 21 | return workspace.getConfiguration().get('marklogic.sparqlGraphResponseType') as ml.SparqlResponseFormat 22 | } 23 | case 'ask': 24 | { 25 | return workspace.getConfiguration().get('marklogic.sparqlAskResponseType') as ml.SparqlResponseFormat 26 | } 27 | default: 28 | { 29 | return 'application/json' //Malformatted SPARQL - format for error 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /client/test/integration/Issue69.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable @typescript-eslint/no-use-before-define */ 18 | import * as Path from 'path'; 19 | import { DebugClient } from '@vscode/debugadapter-testsupport'; 20 | import { DebugProtocol } from '@vscode/debugprotocol'; 21 | import * as CP from 'child_process'; 22 | 23 | import { IntegrationTestHelper, wait } from './markLogicIntegrationTestHelper'; 24 | import { JsDebugManager } from '../../JSDebugger/jsDebugManager'; 25 | 26 | 27 | suite('Issue 69', async () => { 28 | const integrationTestHelper: IntegrationTestHelper = globalThis.integrationTestHelper; 29 | 30 | test('set breakpoints on two files', async () => { 31 | await integrationTestHelper.restartMarkLogicAndWaitUntilItIsAvailableAgain(); 32 | const globalConfig = integrationTestHelper.config; 33 | await JsDebugManager.connectToNamedJsDebugServer(integrationTestHelper.attachServerName); 34 | globalThis.integrationTestHelper.attachedToServer = true; 35 | 36 | const curlCommand = `curl --anyauth -k --user ${globalConfig.username}:${globalConfig.password} -i -X POST -H "Content-type: application/x-www-form-urlencoded" \ 37 | http${globalConfig.ssl ? 's' : ''}://${globalConfig.hostname}:${integrationTestHelper.serverPortForAttaching}/LATEST/invoke --data-urlencode module=/MarkLogic/test/test.sjs`; 38 | CP.exec(curlCommand); 39 | await wait(1000); 40 | const serverName = integrationTestHelper.attachServerName; 41 | const resp = await integrationTestHelper.getRid(integrationTestHelper.mlClient, `xdmp.serverStatus(xdmp.host(),xdmp.server('${serverName}')).toObject()[0].requestStatuses[0].requestId`); 42 | const rid = resp[0]; 43 | const root = Path.join(integrationTestHelper.jsScriptFolder, 'MarkLogic/test'); 44 | const config = { 45 | rid: rid, root: root, 46 | username: globalConfig.username, password: globalConfig.password, 47 | hostname: globalConfig.hostname, managePort: integrationTestHelper.managePort, 48 | database: integrationTestHelper.modulesDatabase, modules: integrationTestHelper.modulesDatabase, 49 | authType: 'BASIC', ssl: globalConfig.ssl, 50 | pathToCa: globalConfig.pathToCa, rejectUnauthorized: globalConfig.rejectUnauthorized 51 | }; 52 | const jsDebugClient: DebugClient = integrationTestHelper.jsDebugClient; 53 | await Promise.all([ 54 | jsDebugClient.initializeRequest(), 55 | jsDebugClient.configurationSequence(), 56 | jsDebugClient.attachRequest(config as DebugProtocol.AttachRequestArguments) 57 | ]); 58 | 59 | await jsDebugClient.setBreakpointsRequest({ source: { path: Path.join('/MarkLogic/test', 'test.sjs') }, breakpoints: [{ line: 20 }] }); 60 | await jsDebugClient.setBreakpointsRequest({ source: { path: Path.join('/MarkLogic/test', 'lib1.sjs') }, breakpoints: [{ line: 18 }] }); 61 | await jsDebugClient.setBreakpointsRequest({ source: { path: Path.join('/MarkLogic/test', 'lib2.sjs') }, breakpoints: [{ line: 18 }] }); 62 | await jsDebugClient.continueRequest({ threadId: 1 }); 63 | await jsDebugClient.waitForEvent('stopped'); 64 | await jsDebugClient.continueRequest({ threadId: 1 }); 65 | await jsDebugClient.waitForEvent('stopped'); 66 | await jsDebugClient.continueRequest({ threadId: 1 }); 67 | await jsDebugClient.waitForEvent('stopped'); 68 | await jsDebugClient.continueRequest({ threadId: 1 }); 69 | await jsDebugClient.assertStoppedLocation('breakpoint', { path: Path.join('/MarkLogic/test', 'test.sjs'), line: 20 }); 70 | await jsDebugClient.setBreakpointsRequest({ source: { path: Path.join('/MarkLogic/test', 'test.sjs') }, breakpoints: [] }); 71 | await jsDebugClient.setBreakpointsRequest({ source: { path: Path.join('/MarkLogic/test', 'lib1.sjs') }, breakpoints: [] }); 72 | await jsDebugClient.setBreakpointsRequest({ source: { path: Path.join('/MarkLogic/test', 'lib2.sjs') }, breakpoints: [] }); 73 | await jsDebugClient.continueRequest({ threadId: 1 }); 74 | }).timeout(15000); 75 | }); 76 | -------------------------------------------------------------------------------- /client/test/integration/Issue70.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable @typescript-eslint/no-use-before-define */ 18 | import * as assert from 'assert'; 19 | import * as Path from 'path'; 20 | import { DebugClient } from '@vscode/debugadapter-testsupport'; 21 | import { DebugProtocol } from '@vscode/debugprotocol'; 22 | import * as CP from 'child_process'; 23 | import * as fs from 'fs'; 24 | 25 | import { IntegrationTestHelper, wait } from './markLogicIntegrationTestHelper'; 26 | import { JsDebugManager } from '../../JSDebugger/jsDebugManager'; 27 | 28 | 29 | suite('Issue 70', async () => { 30 | const integrationTestHelper: IntegrationTestHelper = globalThis.integrationTestHelper; 31 | 32 | test('check non-existing modules are loaded', async () => { 33 | const globalConfig = integrationTestHelper.config; 34 | await JsDebugManager.connectToNamedJsDebugServer(integrationTestHelper.attachServerName); 35 | globalThis.integrationTestHelper.attachedToServer = true; 36 | const jsScriptFolder = integrationTestHelper.jsScriptFolder; 37 | const path = Path.join(jsScriptFolder, 'helloWorld.sjs'); 38 | const text = fs.readFileSync(path).toString(); 39 | 40 | CP.exec(`curl --anyauth -k --user ${globalConfig.username}:${globalConfig.password} -i -X POST -H "Content-type: application/x-www-form-urlencoded" \ 41 | http${globalConfig.ssl ? 's' : ''}://${globalConfig.hostname}:${integrationTestHelper.serverPortForAttaching}/LATEST/invoke --data-urlencode module=/MarkLogic/test/helloWorld.sjs`); 42 | await wait(1000); 43 | const serverName = integrationTestHelper.attachServerName; 44 | const resp = await integrationTestHelper.getRid(integrationTestHelper.mlClient, `xdmp.serverStatus(xdmp.host(),xdmp.server('${serverName}')).toObject()[0].requestStatuses[0].requestId`); 45 | const rid = resp[0]; 46 | const root = Path.join(integrationTestHelper.jsScriptFolder, 'MarkLogic/test'); 47 | const config = { 48 | rid: rid, root: root, 49 | username: globalConfig.username, password: globalConfig.password, 50 | hostname: globalConfig.hostname, managePort: integrationTestHelper.managePort, 51 | database: integrationTestHelper.modulesDatabase, modules: integrationTestHelper.modulesDatabase, 52 | authType: 'BASIC', ssl: globalConfig.ssl, 53 | pathToCa: globalConfig.pathToCa, rejectUnauthorized: globalConfig.rejectUnauthorized 54 | }; 55 | const jsDebugClient: DebugClient = integrationTestHelper.jsDebugClient; 56 | await Promise.all([ 57 | jsDebugClient.initializeRequest(), 58 | jsDebugClient.configurationSequence(), 59 | jsDebugClient.attachRequest(config as DebugProtocol.AttachRequestArguments) 60 | ]); 61 | const stackResponse = await jsDebugClient.stackTraceRequest({ threadId: 1 }); 62 | const src = stackResponse['body']['stackFrames'][0]['source']; 63 | assert.equal(9, src['sourceReference'], 'confrim stackFrame source id indicates non-existing file'); 64 | const srcReqResponse = await jsDebugClient.sourceRequest({ source: src, sourceReference: src.sourceReference }); 65 | assert.equal(srcReqResponse['body']['content'], text, 'check if modules is streamed back'); 66 | await jsDebugClient.continueRequest({ threadId: 1 }); 67 | }).timeout(10000); 68 | 69 | }); 70 | -------------------------------------------------------------------------------- /client/test/integration/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as glob from 'glob'; 18 | import * as Mocha from 'mocha'; 19 | import * as path from 'path'; 20 | import * as vscode from 'vscode'; 21 | 22 | import { IntegrationTestHelper } from './markLogicIntegrationTestHelper'; 23 | 24 | export async function run(): Promise { 25 | const mocha = new Mocha({ 26 | ui: 'tdd' 27 | }); 28 | globalThis.integrationTestHelper = new IntegrationTestHelper(); 29 | await globalThis.integrationTestHelper.beforeEverything(); 30 | 31 | // Without extending the setup, only 1 reporter is support. 32 | // For available reporters, see https://mochajs.org/#reporters 33 | // For options on configuring multiple reports, see: 34 | // https://github.com/mochajs/mocha/pull/1360 35 | // https://github.com/glenjamin/mocha-multi 36 | const resultsFileName = __dirname + '/../../../results/integrationTestResults.xml'; 37 | mocha.reporter('spec'); 38 | // Use the 'xunit' reporter when we want file output for automation 39 | // mocha.reporter('xunit', { output: resultsFileName }); 40 | 41 | mocha.options.color = true; 42 | // Need to set the timeout a little high since some tests require a server restart 43 | // 10s is a little arbitrary, but it works. 44 | // We could set the timeout lower, but that would only save time when things are broken. 45 | mocha.timeout(10000); 46 | mocha.rootHooks({ 47 | beforeEach: async () => { 48 | await globalThis.integrationTestHelper.setupEachTest(); 49 | }, 50 | afterEach: async () => { 51 | await globalThis.integrationTestHelper.teardownEachTest(); 52 | } 53 | }); 54 | 55 | const testsRoot = path.resolve(__dirname, '..'); 56 | 57 | return new Promise((c, e) => { 58 | // We can change the value below to run specific test files. 59 | // glob('integration/marklogicClient.test.js', { cwd: testsRoot }, (err, files) => { 60 | glob('integration/**.test.js', { cwd: testsRoot }, (err, files) => { 61 | console.debug(JSON.stringify(files)); 62 | vscode.window.showInformationMessage(JSON.stringify(files)); 63 | if (err) { 64 | return e(err); 65 | } 66 | // Add files to the test suite 67 | files.forEach(f => { 68 | mocha.addFile(path.resolve(testsRoot, f)); 69 | }); 70 | 71 | try { 72 | // Run the mocha test 73 | mocha.run(failures => { 74 | if (failures > 0) { 75 | vscode.window.showErrorMessage(`${failures} tests failed.`); 76 | e(new Error(`${failures} tests failed.`)); 77 | } else { 78 | vscode.window.showInformationMessage('No failures reported'); 79 | c(); 80 | } 81 | }); 82 | } catch (err) { 83 | e(err); 84 | } 85 | }); 86 | }); 87 | } 88 | -------------------------------------------------------------------------------- /client/test/integration/integration.env: -------------------------------------------------------------------------------- 1 | ML_HOST=localhost 2 | ML_PORT=8055 3 | ML_MANAGEPORT=8059 4 | ML_USERNAME=admin 5 | ML_PASSWORD=admin 6 | ML_MODULESDB=mlxprs-test-modules 7 | -------------------------------------------------------------------------------- /client/test/integration/jsScripts/MarkLogic/test/invoke1.xqy: -------------------------------------------------------------------------------- 1 | (: 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | :) 16 | 17 | xquery version "1.0-ml"; 18 | declare namespace my="my-namespace-uri"; 19 | xdmp:invoke("/MarkLogic/test/jsInvoke-1.sjs") -------------------------------------------------------------------------------- /client/test/integration/jsScripts/MarkLogic/test/jsInvoke-1.sjs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const eval1 = 1; 18 | const eval2 = 2; 19 | const eval3 = 3; 20 | eval1 + eval2 + eval3; -------------------------------------------------------------------------------- /client/test/integration/jsScripts/MarkLogic/test/jsInvoke-2.sjs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const a = 'a'; 18 | 19 | const evalRes = xdmp.invoke('/MarkLogic/test/xqyInvoke-1.xqy'); 20 | 21 | evalRes; -------------------------------------------------------------------------------- /client/test/integration/jsScripts/MarkLogic/test/lib1.sjs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const foo = function () { 18 | let i = 12; 19 | i = i * i; 20 | i = i + 1; 21 | return i; 22 | }; 23 | 24 | module.exports = foo; -------------------------------------------------------------------------------- /client/test/integration/jsScripts/MarkLogic/test/lib2.sjs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const bar = function () { 18 | let i = 12; 19 | i = i * i; 20 | i = i + 1; 21 | return i; 22 | }; 23 | module.exports = bar; -------------------------------------------------------------------------------- /client/test/integration/jsScripts/MarkLogic/test/test.sjs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable @typescript-eslint/no-var-requires */ 18 | for (let i = 0; i < 30; i++) { 19 | const r = 0; 20 | const m = 1; 21 | 22 | const foo = require('/MarkLogic/test/lib1.sjs'); 23 | const bar = require('/MarkLogic/test/lib2.sjs'); 24 | const res = r + m + foo() + bar(); 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /client/test/integration/jsScripts/MarkLogic/test/xqyInvoke-1.xqy: -------------------------------------------------------------------------------- 1 | (: 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | :) 16 | 17 | xquery version "1.0-ml"; 18 | for $i in (1 to 10) 19 | return $i * 2 -------------------------------------------------------------------------------- /client/test/integration/jsScripts/eval1.sjs: -------------------------------------------------------------------------------- 1 | const a = 'a'; 2 | const b = 'b'; 3 | const c = 'c'; 4 | const evalRes = xdmp.eval( 5 | 'let eval1 = 1\n\ 6 | let eval2 = 2\n\ 7 | let eval3 = 3\n\ 8 | eval1 + eval2 + eval3'); 9 | evalRes; -------------------------------------------------------------------------------- /client/test/integration/jsScripts/eval2.sjs: -------------------------------------------------------------------------------- 1 | const a = 'a'; 2 | const b = 'b'; 3 | const c = 'c'; 4 | const evalRes = xdmp.xqueryEval( 5 | 'xquery version "1.0-ml";\n\ 6 | for $i in (1 to 10)\n\ 7 | return $i * 2'); 8 | evalRes; -------------------------------------------------------------------------------- /client/test/integration/jsScripts/eval3.sjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-var */ 2 | /* eslint-disable @typescript-eslint/no-var-requires */ 3 | var admin = require('/MarkLogic/admin.xqy'); 4 | var config = admin.getConfiguration(); 5 | 6 | var str = 'testing import'; 7 | str; -------------------------------------------------------------------------------- /client/test/integration/jsScripts/helloWorld.sjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-use-before-define */ 2 | /* eslint-disable @typescript-eslint/explicit-function-return-type */ 3 | const str = 'Hello World SJS'; 4 | const str2 = 'line 2'; 5 | const str3 = 'line 3'; 6 | const num = loop(); 7 | const str4 = 'line 4'; 8 | const str5 = 'line 5'; 9 | 10 | 11 | function loop() { 12 | let ret = 0; 13 | for (let i = 0; i < 30; i++) { 14 | ret += i; 15 | } 16 | return ret; 17 | } -------------------------------------------------------------------------------- /client/test/integration/jsScripts/invoke1.sjs: -------------------------------------------------------------------------------- 1 | const a = 'a'; 2 | const b = 'b'; 3 | const c = 'c'; 4 | const evalRes = xdmp.invoke('/MarkLogic/test/jsInvoke-1.sjs', {}, { 'modules': xdmp.database('%%MODULES-DATABASE%%') }); 5 | 6 | evalRes; -------------------------------------------------------------------------------- /client/test/integration/jsScripts/invoke2.sjs: -------------------------------------------------------------------------------- 1 | const a = 'a'; 2 | const b = 'b'; 3 | const c = 'c'; 4 | const evalRes = xdmp.invoke('/MarkLogic/test/xqyInvoke-1.xqy', {}, { 'modules': xdmp.database('%%MODULES-DATABASE%%') }); 5 | 6 | evalRes; -------------------------------------------------------------------------------- /client/test/integration/jsScripts/nestedInvoke1.sjs: -------------------------------------------------------------------------------- 1 | const a = 'a'; 2 | const b = 'b'; 3 | const c = 'c'; 4 | const evalRes = xdmp.invoke('/MarkLogic/test/jsInvoke-2.sjs', {}, { 'modules': xdmp.database('%%MODULES-DATABASE%%') }); 5 | 6 | 7 | evalRes; 8 | -------------------------------------------------------------------------------- /client/test/integration/marklogicUnitTest.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { XMLParser } from 'fast-xml-parser'; 19 | 20 | import { ClientContext, requestMarkLogicUnitTest } from '../../marklogicClient'; 21 | import { IntegrationTestHelper } from './markLogicIntegrationTestHelper'; 22 | 23 | const options = { 24 | ignoreAttributes: false, 25 | attributeNamePrefix: '@_', 26 | format: true 27 | }; 28 | 29 | suite('Testing MarkLogic-Unit-Test functionality', async () => { 30 | const integrationTestHelper: IntegrationTestHelper = globalThis.integrationTestHelper; 31 | 32 | test('When a test is requested that should pass completely', async () => { 33 | const mlUnitTestClient: ClientContext = integrationTestHelper.mlUnitTestClientParameters.newMarklogicTestClient(); 34 | await requestMarkLogicUnitTest(mlUnitTestClient, 'SampleJavaScriptTestSuite', 'sample-jstest.sjs') 35 | .result((testResults: string) => { 36 | const parser = new XMLParser(options); 37 | const jObj = parser.parse(testResults); 38 | assert.equal(jObj['test:suite']['@_failed'], '0', 'Then there should be 0 failing tests'); 39 | }) 40 | .catch(error => { 41 | console.debug(error); 42 | assert.fail(`Then the call to MarkLogic should succeed (even if the tests fail): ${error.message}`); 43 | }); 44 | }).timeout(5000); 45 | 46 | test('When a test is requested that does not exist', async () => { 47 | const mlUnitTestClient: ClientContext = integrationTestHelper.mlUnitTestClientParameters.newMarklogicTestClient(); 48 | await requestMarkLogicUnitTest(mlUnitTestClient, 'SampleJavaScriptTestSuite', 'doesNotExist.sjs') 49 | .result((testResults: string) => { 50 | const parser = new XMLParser(options); 51 | const jObj = parser.parse(testResults); 52 | assert.equal(jObj['test:suite']['@_failed'], '1', 'Then there should be 1 failing tests'); 53 | assert.equal(jObj['test:suite']['@_passed'], '0', 'Then there should be 0 passing tests'); 54 | assert.equal(jObj['test:suite']['test:test']['test:result']['error:error']['error:code'], 'XDMP-MODNOTFOUND', 'Then the failure should be due to a module not found'); 55 | }) 56 | .catch(error => { 57 | console.debug(error); 58 | assert.fail(`Then the call to MarkLogic should succeed (even if the tests fail): ${error.message}`); 59 | }); 60 | }).timeout(5000); 61 | 62 | test('When a test is requested that should have a failing test', async () => { 63 | const mlUnitTestClient: ClientContext = integrationTestHelper.mlUnitTestClientParameters.newMarklogicTestClient(); 64 | await requestMarkLogicUnitTest(mlUnitTestClient, 'SampleJavaScriptTestSuite', 'sample-failing-jstest.sjs') 65 | .result((testResults: string) => { 66 | const parser = new XMLParser(options); 67 | const jObj = parser.parse(testResults); 68 | assert.equal(jObj['test:suite']['@_failed'], '1', 'Then there should be 1 failing tests'); 69 | assert.equal(jObj['test:suite']['@_passed'], '0', 'Then there should be 0 passing tests'); 70 | assert.equal(jObj['test:suite']['test:test']['test:result']['error:error']['error:message'], 'expected: 0 actual: 2', 'Then the failure should be due to an unexpected value'); 71 | }) 72 | .catch(error => { 73 | console.debug(error); 74 | assert.fail(`Then the call to MarkLogic should succeed (even if the tests fail): ${error.message}`); 75 | }); 76 | }).timeout(5000); 77 | 78 | }); 79 | -------------------------------------------------------------------------------- /client/test/integration/xqyAdapter.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { IntegrationTestHelper } from './markLogicIntegrationTestHelper'; 18 | 19 | suite('Testing xqy debugging', async () => { 20 | const integrationTestHelper: IntegrationTestHelper = globalThis.integrationTestHelper; 21 | 22 | test('xqy calling xdmp:eval()', async () => { 23 | const xqyDebugClient = integrationTestHelper.xqyDebugClient; 24 | const xqyConfig = integrationTestHelper.xqyConfig; 25 | 26 | await Promise.all([ 27 | xqyDebugClient.configurationSequence(), 28 | xqyDebugClient.launch(xqyConfig) 29 | ]); 30 | 31 | await xqyDebugClient.setBreakpointsRequest({ source: { path: xqyConfig.program }, breakpoints: [{ line: 22 }] }); 32 | await xqyDebugClient.continueRequest({ threadId: 1 }); 33 | await xqyDebugClient.assertStoppedLocation('breakpoint', { path: xqyConfig.program, line: 22 }); 34 | await xqyDebugClient.continueRequest({ threadId: 1 }); 35 | }).timeout(25000); 36 | 37 | }); 38 | -------------------------------------------------------------------------------- /client/test/integration/xqyScripts/factorial.xqy: -------------------------------------------------------------------------------- 1 | xquery version "1.0-ml"; 2 | 3 | declare function local:factorial( 4 | $n as xs:unsignedLong? 5 | ) as xs:unsignedLong { 6 | if (fn:empty($n) or $n le 1) then 7 | 1 8 | else 9 | $n * local:factorial( 10 | $n - 1 11 | ) 12 | }; 13 | 14 | let $_ := xdmp:log("running longTest.xqy") 15 | let $three := 3 16 | let $steps := (1, 2, $three) 17 | let $squares := 18 | for $step in $steps 19 | return $step * $step 20 | let $_ := xdmp:log(("Squares", $squares)) 21 | let $result := local:factorial(5) 22 | let $_ := xdmp:log(("Factorial result", $result)) 23 | return $result -------------------------------------------------------------------------------- /client/test/runIntegrationTest.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as path from 'path'; 18 | 19 | import { runTests } from '@vscode/test-electron'; 20 | 21 | async function main(): Promise { 22 | try { 23 | // The folder containing the Extension Manifest package.json 24 | // Passed to `--extensionDevelopmentPath` 25 | const extensionDevelopmentPath = path.resolve(__dirname, '../..'); 26 | 27 | // The path to the extension test runner script 28 | // Passed to --extensionTestsPath 29 | const extensionTestsPath = path.resolve(__dirname, './integration/index'); 30 | 31 | // Download VS Code, unzip it and run the integration test 32 | await runTests( 33 | { 34 | extensionDevelopmentPath, 35 | extensionTestsPath, 36 | launchArgs: [ 37 | '--disable-extensions' 38 | ] 39 | } 40 | ); 41 | } catch (err) { 42 | console.error('Failed to run tests'); 43 | process.exit(1); 44 | } 45 | } 46 | 47 | main(); 48 | -------------------------------------------------------------------------------- /client/test/runTest.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as path from 'path'; 18 | 19 | import { runTests } from '@vscode/test-electron'; 20 | 21 | async function main(): Promise { 22 | try { 23 | // The folder containing the Extension Manifest package.json 24 | // Passed to `--extensionDevelopmentPath` 25 | const extensionDevelopmentPath = path.resolve(__dirname, '../../../../'); 26 | 27 | // The path to the extension test runner script 28 | // Passed to --extensionTestsPath 29 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 30 | 31 | // Download VS Code, unzip it and run the integration test 32 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 33 | } catch (err) { 34 | console.error('Failed to run tests'); 35 | process.exit(1); 36 | } 37 | } 38 | 39 | main(); 40 | -------------------------------------------------------------------------------- /client/test/suite/defaultDb.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | 19 | import { ClientFactory } from '../../clientFactory'; 20 | 21 | suite('Default Documents DB Test Suite', () => { 22 | test('When ClientFactory is used and the default contentDb is null', async () => { 23 | const mlClient = 24 | new ClientFactory({ 25 | host: 'host', 26 | port: 'port', 27 | user: 'user', 28 | password: 'pwd', 29 | authType: 'DIGEST', 30 | contentDb: null, 31 | modulesDb: 'modulesDb', 32 | ssl: 'ssl', 33 | rejectUnauthorized: 'rejectUnauthorized' 34 | }).newMarklogicRestClient(); 35 | assert.strictEqual(mlClient.params.contentDb, null, 'ML client contentDb should be null'); 36 | }); 37 | 38 | test('When ClientFactory is used and the default contentDb is undefined', async () => { 39 | const mlClient = 40 | new ClientFactory({ 41 | host: 'host', 42 | port: 'port', 43 | user: 'user', 44 | password: 'pwd', 45 | authType: 'DIGEST', 46 | contentDb: undefined, 47 | modulesDb: 'modulesDb', 48 | ssl: 'ssl', 49 | rejectUnauthorized: 'rejectUnauthorized' 50 | }).newMarklogicRestClient(); 51 | assert.strictEqual(mlClient.params.contentDb, null, 'ML client contentDb should be null'); 52 | }); 53 | 54 | test('When ClientFactory is used and the default contentDb is \'\'', async () => { 55 | const mlClient = 56 | new ClientFactory({ 57 | host: 'host', 58 | port: 'port', 59 | user: 'user', 60 | password: 'pwd', 61 | authType: 'DIGEST', 62 | contentDb: '', 63 | modulesDb: 'modulesDb', 64 | ssl: 'ssl', 65 | rejectUnauthorized: 'rejectUnauthorized' 66 | }).newMarklogicRestClient(); 67 | assert.strictEqual(mlClient.params.contentDb, null, 'ML client contentDb should be null'); 68 | }); 69 | 70 | test('When ClientFactory is used and the default contentDb is missing', async () => { 71 | const mlClient = 72 | new ClientFactory({ 73 | host: 'host', 74 | port: 'port', 75 | user: 'user', 76 | password: 'pwd', 77 | authType: 'DIGEST', 78 | modulesDb: 'modulesDb', 79 | ssl: 'ssl', 80 | rejectUnauthorized: 'rejectUnauthorized' 81 | }).newMarklogicRestClient(); 82 | assert.strictEqual(mlClient.params.contentDb, null, 'ML client contentDb should be null'); 83 | }); 84 | 85 | test('When ClientFactory is used and the default contentDb contains a value', async () => { 86 | const params = { 87 | host: 'host', 88 | port: 'port', 89 | user: 'user', 90 | password: 'pwd', 91 | authType: 'DIGEST', 92 | contentDb: 'someDatabase', 93 | modulesDb: 'modulesDb', 94 | ssl: 'ssl', 95 | rejectUnauthorized: 'rejectUnauthorized' 96 | }; 97 | const clientFactory = new ClientFactory(params); 98 | const mlClient = clientFactory.newMarklogicRestClient(); 99 | assert.strictEqual(mlClient.params.contentDb, 'someDatabase', 'ML client contentDb should match the input value'); 100 | }); 101 | 102 | }); 103 | -------------------------------------------------------------------------------- /client/test/suite/dummyGlobalState.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | import { Memento } from 'vscode'; 20 | import { ClientContext } from '../../marklogicClient'; 21 | import { ClientFactory } from '../../clientFactory'; 22 | 23 | /** 24 | * 25 | */ 26 | export class DummyGlobalState implements Memento { 27 | dummyClient: ClientContext; 28 | get(key: string): T 29 | get(key: string, defaultValue: T): T 30 | 31 | get(key: any, defaultValue?: any): ClientContext { 32 | return this.dummyClient; 33 | } 34 | update(key: string, value: any): Thenable { 35 | return new Promise(() => { 36 | this.dummyClient = value as ClientContext; 37 | }); 38 | } 39 | 40 | constructor(dummyClient: ClientContext) { 41 | this.dummyClient = dummyClient; 42 | } 43 | keys(): readonly string[] { 44 | throw new Error('Method not implemented.'); 45 | } 46 | } 47 | 48 | export function defaultDummyGlobalState(): DummyGlobalState { 49 | const dbClient = new ClientFactory({ 50 | host: 'nohost', port: 0, user: 'user', password: 'pwd', 51 | authType: 'BASIC', contentDb: 'DOCS', modulesDb: 'MODS', 52 | ssl: true, pathToCa: '' 53 | }).newMarklogicRestClient(); 54 | dbClient.params.sameAs = function (): boolean { 55 | return false; 56 | }; 57 | return new DummyGlobalState(dbClient); 58 | } 59 | -------------------------------------------------------------------------------- /client/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as path from 'path'; 18 | import * as Mocha from 'mocha'; 19 | import * as glob from 'glob'; 20 | 21 | export function run(): Promise { 22 | // Create the mocha test 23 | const mocha = new Mocha({ 24 | ui: 'tdd' 25 | }); 26 | mocha.options.color = true; 27 | 28 | const testsRoot = path.resolve(__dirname, '..'); 29 | 30 | return new Promise((c, e) => { 31 | // glob('suite/defaultDb.test.js', { cwd: testsRoot }, (err, files) => { 32 | glob('suite/**.test.js', { cwd: testsRoot }, (err, files) => { 33 | if (err) { 34 | return e(err); 35 | } 36 | 37 | // Add files to the test suite 38 | files.forEach(f => { 39 | mocha.addFile(path.resolve(testsRoot, f)); 40 | }); 41 | 42 | try { 43 | // Run the mocha test 44 | mocha.run(failures => { 45 | if (failures > 0) { 46 | e(new Error(`${failures} tests failed.`)); 47 | } else { 48 | c(); 49 | } 50 | }); 51 | } catch (err) { 52 | e(err); 53 | } 54 | }); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /client/test/suite/rowsQuery.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import * as ml from 'marklogic'; 19 | 20 | import { defaultDummyGlobalState } from './dummyGlobalState'; 21 | import { sendRows } from '../../marklogicClient'; 22 | 23 | const dslQuery = 'op.fromView()'; 24 | const serializedQueryString = '{ "$optic": { "ns": "op", "fn": "operators", "args": [{ "ns": "op", "fn": "from-view", "args": ["Medical", "Authors"] }] } }'; 25 | const rowsResponseFormats: ml.RowsResponseFormat[] = ['json', 'xml', 'csv']; 26 | 27 | let calculatedOptions: ml.RowsOptions; 28 | let calculatedQuery: object | string; 29 | function dummyRowsQuerier(): ml.Rows { 30 | return { 31 | query: (actualQuery: object | string, options: ml.RowsOptions): Promise => { 32 | calculatedQuery = actualQuery; 33 | calculatedOptions = options; 34 | return null; 35 | }, 36 | graphQL: (actualQuery: object | string): Promise => { 37 | return null; 38 | } 39 | }; 40 | } 41 | const gstate = defaultDummyGlobalState(); 42 | gstate.dummyClient.databaseClient.rows = dummyRowsQuerier(); 43 | 44 | suite('Rows Query Test Suite', () => { 45 | 46 | test('When an Optic DSL query is passed into the sendRows function', async () => { 47 | rowsResponseFormats.forEach((rowsResponseFormat) => { 48 | const rowsQueryType: ml.RowsQueryType = 'dsl'; 49 | const expectedOptions: ml.RowsOptions = { 'queryType': rowsQueryType, 'format': rowsResponseFormat }; 50 | 51 | sendRows(gstate.dummyClient, dslQuery, rowsResponseFormat); 52 | assert.deepEqual(calculatedQuery, dslQuery, `the query is passed as "${rowsQueryType}" to the MarkLogic query function`); 53 | assert.deepEqual(calculatedOptions, expectedOptions, `the options passed to the MarkLogic query function specify "${rowsResponseFormat}"`); 54 | }); 55 | }); 56 | 57 | test('When a serialized Optic query is passed into the sendRows function', async () => { 58 | rowsResponseFormats.forEach((rowsResponseFormat) => { 59 | const rowsQueryType: ml.RowsQueryType = 'json'; 60 | const expectedOptions: ml.RowsOptions = { 'queryType': rowsQueryType, 'format': rowsResponseFormat }; 61 | 62 | sendRows(gstate.dummyClient, serializedQueryString, rowsResponseFormat); 63 | assert.deepEqual(calculatedQuery, JSON.parse(serializedQueryString), `the query is passed as "${rowsQueryType}" to the MarkLogic query function`); 64 | assert.deepEqual(calculatedOptions, expectedOptions, `the options passed to the MarkLogic query function specify "${rowsResponseFormat}"`); 65 | }); 66 | }); 67 | 68 | }); 69 | -------------------------------------------------------------------------------- /client/test/suite/testOverrideQuery.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export function testOverrideQueryWithGoodJSON(): string { 18 | return ` 19 | /* mlxprs:settings 20 | 21 | { 22 | "host": "overrideHost", 23 | "port": 12345, 24 | "username": "blahpblorpbleepybloop" 25 | } 26 | 27 | */ 28 | // Another comment 29 | /* another block comment */ 30 | cts.doc(cts.uris().toArray()[12 + 19]) 31 | `; 32 | } 33 | 34 | export function testOverrideQueryWithBadJSON(): string { 35 | return ` 36 | /* mlxprs:settings 37 | 38 | { 39 | "host": 'overrideHost', 40 | "port": 12345, 41 | "username": "blahpblorpbleepybloop" 42 | } 43 | 44 | */ 45 | // Another comment 46 | /* another block comment */ 47 | cts.doc(cts.uris().toArray()[12 + 19]) 48 | `; 49 | } 50 | 51 | export function testQueryWithoutOverrides(): string { 52 | return ` 53 | /* ignore these settings! 54 | 55 | { 56 | "host": "overrideHost", 57 | "port": 12345, 58 | "username": "blahpblorpbleepybloop" 59 | } 60 | 61 | */ 62 | // Another comment 63 | /* another block comment */ 64 | cts.doc(cts.uris().toArray()[12 + 19]) 65 | `; 66 | } 67 | 68 | export function testOverrideXQueryWithGoodJSON(): string { 69 | return ` 70 | (: mlxprs:settings 71 | 72 | { 73 | "host": "overrideHost", 74 | "port": 12345, 75 | "username": "blahpblorpbleepybloop" 76 | } 77 | 78 | :) 79 | (: Another comment :) 80 | cts:doc(cts:uris()[12 + 19]) 81 | `; 82 | } 83 | 84 | export function testOverrideXQueryWithBadJSON(): string { 85 | return ` 86 | 87 | (: mlxprs:settings 88 | 89 | { 90 | "host": 'overrideHost', 91 | "port": 12345, 92 | "username": "blahpblorpbleepybloop" 93 | } 94 | 95 | :) 96 | (: Another comment :) 97 | (: another comment :) 98 | cts:doc(cts:uris()[12 + 19]) 99 | `; 100 | } 101 | 102 | export function testXQueryWithoutOverrides(): string { 103 | return ` 104 | (: ignore these settings! 105 | 106 | { 107 | "host": "overrideHost", 108 | "port": 12345, 109 | "username": "blahpblorpbleepybloop" 110 | } 111 | 112 | :) 113 | (: Another comment 114 | another block comment :) 115 | cts.doc(cts.uris().toArray()[12 + 19]) 116 | `; 117 | } 118 | 119 | export function testOverrideSslParams(): string { 120 | return ` 121 | /* mlxprs:settings 122 | { 123 | "host": "127.0.0.1", 124 | "ssl": true, 125 | "rejectUnauthorized": false 126 | } 127 | */ 128 | 'This is your bank. Please login kthx...' 129 | `; 130 | } 131 | -------------------------------------------------------------------------------- /client/test/suite/xqyRuntime.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { after, before } from 'mocha'; 19 | 20 | import { window } from 'vscode'; 21 | import { testStackXml, testExprXml, testLargerStackXml } from './testXqyDebugMessages'; 22 | import { XqyRuntime, XqyFrame, XqyExpr } from '../../XQDebugger/xqyRuntime'; 23 | 24 | suite('XQyuery Debug Test Suite', () => { 25 | let stackFrames: Array; 26 | let largerStackFrames: Array; 27 | let expr: Array; 28 | const stackXmlString: string = testStackXml(); 29 | const largerStackXmlString: string = testLargerStackXml(); 30 | const exprXmlString: string = testExprXml(); 31 | 32 | after(() => { 33 | window.showInformationMessage('All tests done!'); 34 | }); 35 | 36 | before(() => { 37 | stackFrames = XqyRuntime.parseStackXML(stackXmlString); 38 | largerStackFrames = XqyRuntime.parseStackXML(largerStackXmlString); 39 | expr = XqyRuntime.parseExprXML(exprXmlString); 40 | }); 41 | 42 | test('parseStackXML produces XqyFrames', () => { 43 | assert.equal(3, stackFrames.length); 44 | assert.ok(stackFrames[0].operation.match(/for \$row in \$rows let/)); 45 | assert.equal(8, stackFrames[0].line); 46 | assert.equal('/test-module.xqy', stackFrames[0].uri); 47 | assert.equal('9444875716397283355', stackFrames[0].xid); 48 | }); 49 | 50 | test('parseStackXML produces usable stack', () => { 51 | assert.equal(4, largerStackFrames.length); 52 | }); 53 | 54 | test('parseStackXML produces usable scopeChain', () => { 55 | assert.equal(4, largerStackFrames[0].scopeChain[0].variables.length); 56 | assert.equal('global', largerStackFrames[0].scopeChain[0].type); 57 | assert.equal(5, largerStackFrames[3].scopeChain[0].variables.length); 58 | }); 59 | 60 | test('parseStackXML scopeChains include usable variables', () => { 61 | assert.equal(1, largerStackFrames[3].scopeChain.length); 62 | assert.equal(2, largerStackFrames[2].scopeChain.length); 63 | assert.equal('local', largerStackFrames[2].scopeChain[1].type); 64 | }); 65 | 66 | test('parseStackXML exposes variable values when available', () => { 67 | assert.ok(largerStackFrames[2].scopeChain[1].variables[1].value); 68 | assert.ok(largerStackFrames[2].scopeChain[1].variables[0].value); 69 | assert.equal('map:map()', largerStackFrames[2].scopeChain[1].variables[1].value); 70 | 71 | assert.ok(!largerStackFrames[3].scopeChain[0].variables[0].value); 72 | }); 73 | 74 | test('parseStackXML uses local variables from first frame when available', () => { 75 | assert.equal(2, largerStackFrames[0].scopeChain.length); 76 | assert.ok(largerStackFrames[0].scopeChain.map(scope => { 77 | return scope.type; 78 | }).includes('local')); 79 | }); 80 | 81 | test('parseExprXML produces XqyExprs', () => { 82 | assert.equal(2, expr.length); 83 | assert.equal('3023757983150276589', expr[0].id); 84 | assert.ok(expr[0].source.match(/for \$row in \$rows let/)); 85 | assert.ok(!expr[1].source.match(/for \$row in \$rows let/)); 86 | assert.equal(7, expr[0].line); 87 | assert.equal(10, expr[1].line); 88 | }); 89 | 90 | }); 91 | -------------------------------------------------------------------------------- /client/vscModuleContentProvider.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | import { 20 | Event, EventEmitter, TextDocument, TextDocumentContentProvider, Uri, 21 | window, workspace 22 | } from 'vscode'; 23 | import { ClientContext } from './marklogicClient'; 24 | import { ModuleContentGetter } from './moduleContentGetter'; 25 | 26 | const scheme = 'mlmodule'; 27 | 28 | function encodeLocation(host: string, port: number, path: string): Uri { 29 | const newUri = Uri.parse(`${scheme}://${host}:${port}${path}`); 30 | return newUri; 31 | } 32 | 33 | 34 | export class ModuleContentProvider implements TextDocumentContentProvider { 35 | static scheme = scheme; 36 | private _onDidChange = new EventEmitter(); 37 | private _mlModuleGetter: ModuleContentGetter; 38 | 39 | public initialize(dbClientContext: ClientContext): void { 40 | this._mlModuleGetter = new ModuleContentGetter(dbClientContext); 41 | } 42 | 43 | async provideTextDocumentContent(uri: Uri): Promise { 44 | return this._mlModuleGetter.provideTextDocumentContent(uri.path); 45 | } 46 | 47 | get onDidChange(): Event { 48 | return this._onDidChange.event; 49 | } 50 | 51 | public async listModules(): Promise { 52 | return this._mlModuleGetter.listModules(); 53 | } 54 | } 55 | 56 | export async function pickAndShowModule(mprovider: ModuleContentProvider, dbClientContext: ClientContext): Promise { 57 | mprovider.initialize(dbClientContext); 58 | mprovider.listModules() 59 | .then((moduleUris: string[]) => { 60 | return window.showQuickPick(moduleUris); 61 | }) 62 | .then((URIstring: string) => { 63 | const uri: Uri = encodeLocation(dbClientContext.params.host, dbClientContext.params.port, URIstring); 64 | return uri; 65 | }) 66 | .then((uri: Uri) => { 67 | return workspace.openTextDocument(uri); 68 | }) 69 | .then((doc: TextDocument) => { 70 | window.showTextDocument(doc); 71 | }); 72 | } 73 | -------------------------------------------------------------------------------- /client/vscQueryParameterTools.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | import * as esprima from 'esprima'; 20 | import { WorkspaceConfiguration } from 'vscode'; 21 | 22 | import { buildClientFactoryFromWorkspaceConfig } from './vscodeClientFactory'; 23 | import { 24 | SJS, XQY, parseXQueryForOverrides, MLSETTINGSFLAG, ClientContext, MlClientParameters 25 | } from './marklogicClient'; 26 | import { MlxprsError } from './mlxprsErrorBuilder'; 27 | import { MlxprsErrorReporter } from './mlxprsErrorReporter'; 28 | 29 | /** 30 | * In SJS/XQuery queries, you can override the VS Code mxprs settings in a comment. 31 | * The comment must have the following requirements: 32 | * 33 | * - Block comment as the very first language element in the query 34 | * - the first line of the block comment must include the string 'mlxprs:settings' 35 | * - the rest of the comment must be a valid JSON object 36 | * - the keys of the JSON object are the client parameters you wish to override 37 | * 38 | * @param queryText the text that will be checked for overrides 39 | * @returns a parsed overrides object. Value defined here will be used to override 40 | * what is configured in VS Code 41 | */ 42 | export function parseQueryForOverrides(queryText: string, language: string): Record { 43 | if (language === XQY) { 44 | return parseXQueryForOverrides(queryText); 45 | } 46 | let overrides: Record = {}; 47 | const tokens: esprima.Token[] = esprima.tokenize(queryText, { comment: true, tolerant: true }); 48 | if (tokens.length > 0 && tokens[0].type === 'BlockComment') { 49 | const firstBlockComment: string = tokens[0].value; 50 | const firstBlockCommentLine: string = firstBlockComment.split(/\n+/)[0] 51 | .replace(/\t+/g, '') 52 | .trim(); 53 | if (firstBlockCommentLine.match(MLSETTINGSFLAG)) { 54 | const overridePayload: string = firstBlockComment 55 | .replace(MLSETTINGSFLAG, '') 56 | .trim(); 57 | overrides = JSON.parse(overridePayload); 58 | } 59 | } 60 | return overrides; 61 | } 62 | /** 63 | * Caching mechanism for the ML Client in the extension's state. Checks the configuration for 64 | * changes against the client in the state (i.e. extension's global state) 65 | * 66 | * If the configuration wants a different client than the one in the state, replace the state's 67 | * client with a new one based on the config details. 68 | * 69 | * @param queryText the query to be checked for overrides. Can be left empty ('') if you don't need to parse overrides. 70 | * @param cfg ('config') most likely from `vscode.workspace.getConfiguration()` 71 | * @param language: string SJS or XQY 72 | * @param state most likely the extension's injected `context.globalState` 73 | * 74 | * @returns a MarklogicClient based on the contents of `cfg` 75 | */ 76 | export function getDbClient(queryText: string, language: string, cfg: WorkspaceConfiguration): ClientContext { 77 | const overrides: MlClientParameters = parseQueryForOverrides(queryText, language) as MlClientParameters; 78 | return buildClientFactoryFromWorkspaceConfig(cfg, overrides).newMarklogicRestClient(); 79 | } 80 | 81 | export function getDbClientWithoutOverrides(cfg: WorkspaceConfiguration): ClientContext { 82 | try { 83 | return getDbClient('', SJS, cfg); 84 | } catch (error) { 85 | const mlxprsError: MlxprsError = { 86 | reportedMessage: error.message, 87 | stack: error.stack, 88 | popupMessage: `Unable to build the MarkLogic database client: ${error.message}` 89 | }; 90 | MlxprsErrorReporter.reportError(mlxprsError); 91 | return null; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /client/vscodeClientFactory.ts: -------------------------------------------------------------------------------- 1 | import { WorkspaceConfiguration } from 'vscode'; 2 | 3 | import { ClientFactory } from './clientFactory'; 4 | import { ConfigurationManager } from './configurationManager'; 5 | 6 | // Only use this when you're in a context that has access to the 'vscode' classes. 7 | // This class is necessary because the debugger classes do not have access to the 'vscode' classes. 8 | // By extension, they also do not have access to the ConfigurationManager. 9 | // Therefore, these functions that rely on 'vscode' classes need to be outside of ClientFactory. 10 | export function buildClientFactoryFromWorkspaceConfig( 11 | cfg: WorkspaceConfiguration, 12 | overrides: object = {} 13 | ): ClientFactory { 14 | const configParams: Record = { 15 | host: String(cfg.get('marklogic.host')), 16 | user: String(cfg.get('marklogic.username')), 17 | password: String(cfg.get('marklogic.password')), 18 | pwd: cfg.get('marklogic.password'), 19 | port: Number(cfg.get('marklogic.port')), 20 | restBasePath: String(cfg.get('marklogic.restBasePath')) || '', 21 | managePort: Number(cfg.get('marklogic.managePort')), 22 | manageBasePath: String(cfg.get('marklogic.manageBasePath')) || '', 23 | testPort: Number(cfg.get('marklogic.testPort')), 24 | testBasePath: String(cfg.get('marklogic.testBasePath')) || '', 25 | adminPort: Number(cfg.get('marklogic.adminPort')), 26 | adminBasePath: String(cfg.get('marklogic.adminBasePath')) || '', 27 | contentDb: String(cfg.get('marklogic.documentsDb')), 28 | modulesDb: String(cfg.get('marklogic.modulesDb')), 29 | authType: String(cfg.get('marklogic.authType')).toUpperCase(), 30 | apiKey: String(cfg.get('marklogic.apiKey')), 31 | accessTokenDuration: Number(cfg.get('marklogic.accessTokenDuration')), 32 | ssl: Boolean(cfg.get('marklogic.ssl')), 33 | pathToCa: String(cfg.get('marklogic.pathToCa') || ''), 34 | rejectUnauthorized: Boolean(cfg.get('marklogic.rejectUnauthorized')) 35 | }; 36 | return new ClientFactory({ ...configParams, ...overrides }); 37 | } 38 | 39 | export function buildClientFactoryFromConfigurationManager(): ClientFactory { 40 | const configParams: Record = { 41 | host: ConfigurationManager.getHost(), 42 | user: ConfigurationManager.getUsername(), 43 | password: ConfigurationManager.getPassword(), 44 | port: ConfigurationManager.getPort(), 45 | restBasePath: ConfigurationManager.getRestBasePath(), 46 | managePort: ConfigurationManager.getManagePort(), 47 | manageBasePath: ConfigurationManager.getManageBasePath(), 48 | testPort: ConfigurationManager.getTestPort(), 49 | testBasePath: ConfigurationManager.getTestBasePath(), 50 | adminPort: ConfigurationManager.getAdminPort(), 51 | adminBasePath: ConfigurationManager.getAdminBasePath(), 52 | contentDb: ConfigurationManager.getDocumentsDb(), 53 | modulesDb: ConfigurationManager.getModulesDb(), 54 | authType: ConfigurationManager.getAuthType().toUpperCase(), 55 | apiKey: ConfigurationManager.getApiKey(), 56 | accessTokenDuration: ConfigurationManager.getAccessTokenDuration(), 57 | pathToCa: ConfigurationManager.getPathToCa() || '', 58 | rejectUnauthorized: ConfigurationManager.getRejectUnauthorized() 59 | }; 60 | return new ClientFactory(configParams); 61 | } 62 | -------------------------------------------------------------------------------- /client/xmlFormatting/Formatting.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as vsc from 'vscode'; 4 | import { RangeUtil } from './RangeUtil'; 5 | import { XmlFormatter, IXmlFormatterOptions } from './XmlFormatter'; 6 | 7 | const CFG_SECTION = 'xmlTools'; 8 | const CFG_SPLIT_NAMESPACES = 'splitXmlnsOnFormat'; 9 | 10 | export class XmlFormattingEditProvider implements vsc.DocumentFormattingEditProvider, vsc.DocumentRangeFormattingEditProvider { 11 | provideDocumentFormattingEdits(document: vsc.TextDocument, options: vsc.FormattingOptions): vsc.TextEdit[] { 12 | const range = RangeUtil.getRangeForDocument(document); 13 | 14 | return this._provideFormattingEdits(document, range, options); 15 | } 16 | 17 | provideDocumentRangeFormattingEdits(document: vsc.TextDocument, range: vsc.Range, options: vsc.FormattingOptions): vsc.TextEdit[] { 18 | return this._provideFormattingEdits(document, range, options); 19 | } 20 | 21 | private _provideFormattingEdits(document: vsc.TextDocument, range: vsc.Range, options: vsc.FormattingOptions): vsc.TextEdit[] { 22 | const splitNamespaces: boolean = vsc.workspace.getConfiguration(CFG_SECTION).get(CFG_SPLIT_NAMESPACES, true); 23 | 24 | const formatterOptions: IXmlFormatterOptions = { 25 | preferSpaces: options.insertSpaces, 26 | tabSize: options.tabSize, 27 | splitNamespaces: splitNamespaces 28 | }; 29 | 30 | const formatter = new XmlFormatter(formatterOptions); 31 | const xml = formatter.format(document.getText(range)); 32 | 33 | return [vsc.TextEdit.replace(range, xml)]; 34 | } 35 | } -------------------------------------------------------------------------------- /client/xmlFormatting/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Josh Johnson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /client/xmlFormatting/RangeUtil.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as vsc from 'vscode'; 4 | 5 | export class RangeUtil { 6 | static getRangeForDocument(document: vsc.TextDocument): vsc.Range { 7 | const lastLineIndex = (document.lineCount - 1); 8 | let range = new vsc.Range(new vsc.Position(0, 0), new vsc.Position(lastLineIndex, Number.MAX_VALUE)); 9 | 10 | range = document.validateRange(range); 11 | return range; 12 | } 13 | } -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | .jekyll-cache 4 | .jekyll-metadata 5 | vendor 6 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | # Hello! This is where you manage which Jekyll version is used to run. 3 | # When you want to use a different version, change it below, save the 4 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 5 | # 6 | # bundle exec jekyll serve 7 | # 8 | # This will help ensure the proper Jekyll version is running. 9 | # Happy Jekylling! 10 | 11 | gem "github-pages", "~> 228", group: :jekyll_plugins 12 | 13 | gem "webrick" 14 | 15 | # If you have any plugins, put them here! 16 | group :jekyll_plugins do 17 | # gem "jekyll-feed", "~> 0.12" 18 | end 19 | 20 | # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem 21 | # and associated library. 22 | platforms :mingw, :x64_mingw, :mswin, :jruby do 23 | gem "tzinfo", ">= 1", "< 3" 24 | gem "tzinfo-data" 25 | end 26 | 27 | # Performance-booster for watching directories on Windows 28 | gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] 29 | 30 | # Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem 31 | # do not have a Java counterpart. 32 | gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] 33 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | title: MLXPRS 2 | favicon_ico: "/favicon.ico" 3 | remote_theme: just-the-docs/just-the-docs 4 | plugins: 5 | - jekyll-remote-theme 6 | 7 | heading_anchors: true 8 | 9 | # Aux links for the upper right navigation 10 | aux_links: 11 | "marklogic/mlxprs": 12 | - "https://github.com/marklogic/mlxprs" 13 | 14 | # Makes Aux links open in a new tab. Default is false 15 | aux_links_new_tab: false 16 | 17 | enable_copy_code_button: true 18 | -------------------------------------------------------------------------------- /docs/assets/Progress_PrimarySymbol.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/attach_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marklogic/mlxprs/2be5e05869cd0b820ddd16268196f549a423cb3e/docs/assets/attach_screenshot.png -------------------------------------------------------------------------------- /docs/debugging-support/debugging-support.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Debugging Support 4 | nav_order: 7 5 | has_children: true 6 | permalink: /docs/debugging-support 7 | --- 8 | 9 | ## Debugging 10 | 11 | Both JavaScript and XQuery debuggers support two modes of debugging: 12 | 13 | 1. Launch: Evaluates a main module (for JavaScript) or non-library module (for XQuery) 14 | 2. Attach: Intecepts an existing request, such as from an integration test 15 | 16 | Where it can, query debugging uses the same VS Code settings used for running queries (for example, `marklogic.host`, `marklogic.username`). In addition to these code settings, you will need a [**launch config**](https://code.visualstudio.com/docs/editor/debugging#_launch-configurations) in your project (under `.vscode/launch.json`) for debug-specific parameters. 17 | 18 | Open the `launch.json` from the VS Code command palette with the command: “Debug: Open launch.json” or `Debug`. 19 | 20 | Below is an example of a `launch.json` file, with JavaScript and XQuery configurations for both launch and attach: 21 | 22 | ```json 23 | { 24 | "version": "2.0.0", 25 | "configurations": [ 26 | { 27 | "request": "launch", 28 | "type": "ml-jsdebugger", 29 | "name": "Evaluate Current JavaScript Module" 30 | }, 31 | { 32 | "request": "attach", 33 | "type": "ml-jsdebugger", 34 | "name": "Attach to Debug Request", 35 | "root": "${workspaceFolder}/src/main/ml-modules/root", 36 | "debugServerName": "Enter debug server name" 37 | }, 38 | { 39 | "request": "launch", 40 | "type": "xquery-ml", 41 | "name": "Launch XQY Debug Request", 42 | "program": "", 43 | "root": "${workspaceFolder}/src/main/ml-modules/root" 44 | }, 45 | { 46 | "request": "attach", 47 | "type": "xquery-ml", 48 | "name": "Attach to XQY Debug request", 49 | "root": "${workspaceFolder}/plugins" 50 | } 51 | ] 52 | } 53 | ``` 54 | 55 | VS Code is syntax-aware of what information should go into `launch.json`, so take advantage of auto-complete and hover hints as you edit. 56 | 57 | ### Required Privileges for Evaluation and Debugging 58 | 59 | To run queries with the MarkLogic JavaScript and XQuery Debugger, a user will need eval priviliges on your MarkLogic server. These include: 60 | 61 | - **xdmp-eval**: absolute minimum 62 | - **xdmp-eval-in**: to use a non-default content database 63 | - **xdmp-eval-modules-change**: to use a non-default modules database or modules root 64 | - **xdmp-eval-modules-change-file**: to use the filesystem for modules 65 | 66 | For debugging, a user must also have at least one of these privileges to evaluate a JavaScript or XQuery module in debug mode. 67 | 68 | - **debug-my-requests**: for debugging requests launched by the debug user only 69 | - **debug-any-requests**: for debugging requests launched by any user 70 | 71 | If a user wants to attach to paused requests within a MarkLogic App Server, in order to debug requests, they must have the **debug-any-requests** privilege. 72 | 73 | For more about privileges, see [xdmp:eval](https://docs.marklogic.com/10.0/xdmp:eval) and [Debug functions](https://docs.marklogic.com/dbg) in the API docs, along with [Pre-defined Executive Privileges](https://docs.marklogic.com/guide/admin/exec_privs) in the MarkLogic server documentation. 74 | -------------------------------------------------------------------------------- /docs/debugging-support/localModules.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Launch - Debugging Local Module Evals 4 | nav_order: 1 5 | parent: Debugging Support 6 | --- 7 | 8 | ### Launch - Step Through Local Modules 9 | 10 | Example 'launch' type configuration items for JavaScript and XQuery: 11 | 12 | ```json 13 | { 14 | "type": "ml-jsdebugger", 15 | "request": "launch", 16 | "name": "Evaluate Current JavaScript Module" 17 | }, 18 | { 19 | "type": "xquery-ml", 20 | "request": "launch", 21 | "name": "Launch XQY Debug Request", 22 | "program": "", 23 | "root": "${workspaceFolder}/src/main/ml-modules/root" 24 | } 25 | ``` 26 | 27 | By default, launch mode will launch the currently opened file for debugging. 28 | An optional `program` property can be provided in a `launch.json` task configuration to specify another file for debugging. 29 | Additionally, older versions of this extension permitted the use of `path` for JS. However, while `path` still works, its use is deprecated and will be removed in mlxprs 4.0 30 | -------------------------------------------------------------------------------- /docs/development-support/development-support.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Development Support 4 | nav_order: 4 5 | has_children: true 6 | permalink: /docs/development-support 7 | --- 8 | 9 | Development Support -------------------------------------------------------------------------------- /docs/development-support/tde-templates.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: TDE Templates 4 | nav_order: 1 5 | parent: Development Support 6 | --- 7 | 8 | While developing TDE templates, you may verify that your templates are valid TDE templates. Additionally, if the template is valid, you may also use the template to extract nodes from data documents. That permits you to verify that template is extracting data as intended. 9 | 10 | ### To validate a TDE template: 11 | 1. In an editor tab, open the template file that you wish to be validated. 12 | 2. Open the VS Code command palette. 13 | 3. Select `MarkLogic: Validate TDE Template` from the list 14 | 15 | The results of the validation will appear in the `MLXPRS: RESULTS` tab in the bottom panel. 16 | 17 | ### To extract nodes from a data document using a TDE template: 18 | 1. In an editor tab, open the template file that you wish to use for node extraction. 19 | 2. Add a "var" property with a "name" of "MLXPRS_TEST_URI" and a "val" that is the URI of the data document in the database. If there is not already a "vars" property, you will need to also add that as a child of the "template" property. Alternatively, you can extract data from a local file by using the var "name" of "MLXPRS_TEST_FILE" setting the "val" property to the path to the file. When using "MLXPRS_TEST_FILE", the path in the "val" property may be either an absolute path or a path relative to the current workspace. 20 | 21 | For a JSON document the vars section will look something like the following: 22 | ``` 23 | "vars":[ 24 | { 25 | "name":"MLXPRS_TEST_URI", 26 | "val":"/citations.xml" 27 | } 28 | ] 29 | ``` 30 | 31 | For an XML document the vars section will look something like this: 32 | ``` 33 | 34 | 35 | MLXPRS_TEST_FILE 36 | src/main/ml-data/citations.xml 37 | 38 | 39 | ``` 40 | 41 | 3. Open the VS Code command palette. 42 | 4. Select `MarkLogic: Extract Data Via TDE` from the list 43 | 44 | The results of the node extraction will appear in the `MLXPRS: RESULTS` tab in the bottom panel. 45 | -------------------------------------------------------------------------------- /docs/development-support/viewModules.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: View Database Modules 4 | nav_order: 2 5 | parent: Development Support 6 | --- 7 | 8 | This extension provides an easy method for inspecting the current state of module documents in the database. 9 | You must configure the extension to use your target modules database. See [Installation & Configuration](installationAndConfiguration.md) for information on configuring the extension. 10 | 11 | ### To view a module from the configured modules database: 12 | 13 | 1. Open the VS Code command palette. 14 | 2. Select `MarkLogic: Show Module` from the list. 15 | 3. Choose the module you'd like to view from the resulting list. The list searches and filters as you type. 16 | 17 | The module will appear read-only in a new text buffer. -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marklogic/mlxprs/2be5e05869cd0b820ddd16268196f549a423cb3e/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Introduction 4 | nav_order: 1 5 | --- 6 | 7 | MLXPRS is an extension for Visual Studio Code that simplifies and speeds up the development of applications for MarkLogic. Developers can enjoy all of the benefits that they're accustomed to with Visual Studio Code while leveraging the following features for their MarkLogic applications: 8 | 9 | * Syntax highlighting and IntelliSense for MarkLogic Server-Side JavaScript and XQuery. 10 | * Interactive debugging of JavaScript and XQuery running in MarkLogic, including attaching to in-flight requests and inspecting live variables. 11 | * Real-time query evaluation of JavaScript, XQuery, SQL, SPARQL, Optic, and GraphQL against a MarkLogic instance. 12 | * View modules (read-only) in the editor. 13 | * Run marklogic-unit-test modules. 14 | * Validate TDE templates and test the templates with node extraction. 15 | * View the databases and app servers deployed to the currently configured MarkLogic server. 16 | * View the app-servers that are currently in debug mode on the currently configured MarkLogic server. 17 | * Supports connecting to a MarkLogic server behind a proxy server or in the MarkLogic Cloud. -------------------------------------------------------------------------------- /docs/installationAndConfiguration.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Installation & Configuration 4 | nav_order: 2 5 | --- 6 | 7 | ### Installation 8 | 9 | Install this extension using the VS Code built-in [marketplace](https://marketplace.visualstudio.com/items?itemName=mlxprs.mlxprs). 10 | Search “MarkLogic” from the Extension tab of the activity bar. Click “Install” to download and install the extension. 11 | 12 | 13 | ### Configuration 14 | 15 | The MarkLogic extension may be configured in the VS Code Settings. To open the VS Code Settings editor, choose "Settings..." under the "Code" menu, and then choose "Settings". Once the Settings editor is open, type "MarkLogic" into the search bar. You can also change the configuration settings just for the workspace by adding the values to the `settings.json` file in the .vscode directory of your workspace. 16 | 17 | ##### Direct Connection Configuration Example 18 | ```json 19 | { 20 | "marklogic.host": "localhost", 21 | "marklogic.ssl": false, 22 | "marklogic.authType": "DIGEST", 23 | "marklogic.adminPort": 8001, 24 | "marklogic.adminBasePath": "", 25 | "marklogic.managePort": 8002, 26 | "marklogic.manageBasePath": "", 27 | "marklogic.port": 8040, 28 | "marklogic.restBasePath": "", 29 | "marklogic.testPort": 8041, 30 | "marklogic.testBasePath": "", 31 | "marklogic.username": "username", 32 | "marklogic.password": "****************", 33 | "marklogic.documentsDb": "myproject-content", 34 | "marklogic.modulesDb": "myproject-modules" 35 | } 36 | ``` 37 | 38 | 39 | ##### Reverse Proxy Connection Configuration Example 40 | ```json 41 | { 42 | "marklogic.host": "proxyServer", 43 | "marklogic.ssl": false, 44 | "marklogic.authType": "BASIC", 45 | "marklogic.port": 8020, 46 | "marklogic.restBasePath": "/mlxprs/rest", 47 | "marklogic.managePort": 8020, 48 | "marklogic.manageBasePath": "/mlxprs/manage", 49 | "marklogic.testPort": 8020, 50 | "marklogic.testBasePath": "/mlxprs/test", 51 | "marklogic.adminPort": 8001, 52 | "marklogic.adminBasePath": "", 53 | "marklogic.username": "username", 54 | "marklogic.password": "****************", 55 | "marklogic.documentsDb": "myproject-content", 56 | "marklogic.modulesDb": "myproject-modules" 57 | } 58 | ``` 59 | 60 | 61 | ##### MarkLogic Cloud Connection Configuration Example 62 | ```json 63 | { 64 | "marklogic.host": "support.test.marklogic.cloud", 65 | "marklogic.ssl": true, 66 | "marklogic.authType": "CLOUD", 67 | "marklogic.apiKey": "XXXXXXXXX", 68 | "marklogic.port": 443, 69 | "marklogic.restBasePath": "/ml/test/marklogic/myproject", 70 | "marklogic.managePort": 443, 71 | "marklogic.manageBasePath": "/ml/test/marklogic/manage", 72 | "marklogic.testPort": 443, 73 | "marklogic.testBasePath": "", 74 | "marklogic.adminPort": 443, 75 | "marklogic.adminBasePath": "/ml/test/marklogic/0/admin", 76 | "marklogic.documentsDb": "myproject-content", 77 | "marklogic.modulesDb": "myproject-modules" 78 | } 79 | ``` 80 | 81 | **Note: marklogic.documentsDb must be declared in order to attach to remote JavaScript request.** 82 | 83 | You can also set `marklogic.authType` to `DIGEST` or `BASIC`. Digest is the default, 84 | and works even if the server is running basic authentication. 85 | 86 | ### SSL Configuration 87 | 88 | You can turn on SSL with the `marklogic.ssl` configuration property. 89 | If the CA is not in your chain of trust (for example, if the certificate is self-signed), 90 | you need to point to the CA in your configuration as well using `marklogic.pathToCa`. 91 | The configuration will look something like this: 92 | 93 | ```json 94 | { 95 | "marklogic.ssl": true, 96 | "marklogic.pathToCa": "/Users/myself/certs/my.own.ca.crt" 97 | } 98 | ``` 99 | 100 | You can acquire the CA file from the MarkLogic admin pane (usually port 8001), by 101 | going to 'Security' -> 'Certificate Templates' -> (cert host name), and then 102 | selecting the `Status` tab. There is a `download` button in the `certificate template status` section. Click the `download` button to download a copy of your root CA. 103 | 104 | Alternatively, you can turn off client certificate checks altogether. 105 | Set `marklogic.rejectUnauthorized` to `false` in your VS Code configuration. 106 | This is less secure, but may be useful for situations where you can't obtain or use a your own CA, 107 | such as when connecting to a IP address rather than a hostname. 108 | 109 | Testing with some versions of VS Code has shown that if the project has a file named build.gradle and the VS Code Java Extension is enabled, the `marklogic.rejectUnauthorized` setting may be ignored. If you see this behavior, disabling the Java Extension is recommended to ensure the setting works properly. 110 | 111 | **Note: Currently, all configured ports (port, managePort, and testPort) must have the same SSL settings and they must either use certs that pass the configured CA verification or have CA verification turned off.** 112 | -------------------------------------------------------------------------------- /docs/query-and-script-support/ExecutingGraphQlQueries.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: GraphQL Queries 4 | nav_order: 2 5 | parent: Executing Queries & Scripts 6 | --- 7 | 8 | ### Submit GraphQL Queries 9 | 10 | To run a GraphQL query: 11 | 12 | 1. Type a valid query in the editor. 13 | 2. Open the VS Code command palette. 14 | 3. Select the `MarkLogic: Submit GraphQL Query` command. 15 | 16 | Query results will apper in the `MLXPRS: RESULTS` tab in the bottom panel, or open in a new editor tab - depending on the value of the `Marklogic: Results In Editor Tab` setting. 17 | 18 | For more information on sending GraphQL request to MarkLogic, please refer to [GET /v1/rows/graphql](https://docs.marklogic.com/REST/GET/v1/rows/graphql) and [Introduction to GraphQL with MarkLogic](https://www.marklogic.com/blog/introduction-to-graphql-with-marklogic/). 19 | -------------------------------------------------------------------------------- /docs/query-and-script-support/ExecutingOpticQueries.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Optic Queries 4 | nav_order: 1 5 | parent: Executing Queries & Scripts 6 | --- 7 | 8 | ### Submit Optic Queries 9 | 10 | To run an Optic query (either DSL or serialized): 11 | 12 | 1. Type a valid query in the editor. 13 | 2. Open the VS Code command palette. 14 | 3. Select one of the `MarkLogic: Submit Optic Query - ` commands, depending on the desired response format. 15 | 16 | Query results will apper in the `MLXPRS: RESULTS` tab in the bottom panel, or open in a new editor tab - depending on the value of the `Marklogic: Results In Editor Tab` setting. 17 | -------------------------------------------------------------------------------- /docs/query-and-script-support/ExecutingSparqlQueries.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: SPARQL Queries 4 | nav_order: 4 5 | parent: Executing Queries & Scripts 6 | --- 7 | 8 | ### Evaluate SPARQL Queries 9 | 10 | To evaluate SPARQL: 11 | 12 | 1. Type a valid query in the editor. 13 | 2. Open the VS Code command palette. 14 | 3. Select `MarkLogic: Eval SPARQL`. 15 | 16 | Query results will apper in the `MLXPRS: RESULTS` tab in the bottom panel, or open in a new editor tab - depending on the value of the `Marklogic: Results In Editor Tab` setting. 17 | -------------------------------------------------------------------------------- /docs/query-and-script-support/ExecutingSqlQueries.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: SQL Queries 4 | nav_order: 3 5 | parent: Executing Queries & Scripts 6 | --- 7 | 8 | ### Evaluate SQL Queries 9 | 10 | To evaluate SQL: 11 | 12 | 1. Type a valid query in the editor. 13 | 2. Open the VS Code command palette. 14 | 3. Select `MarkLogic: Eval SQL`. 15 | 16 | Query results will apper in the `MLXPRS: RESULTS` tab in the bottom panel, or open in a new editor tab - depending on the value of the `Marklogic: Results In Editor Tab` setting. 17 | -------------------------------------------------------------------------------- /docs/query-and-script-support/evaluatingModules.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: JS & XQuery Modules 4 | nav_order: 5 5 | parent: Executing Queries & Scripts 6 | --- 7 | 8 | ### Evaluate JavaScript & XQuery modules 9 | 10 | To evaluate JavaScript or XQuery: 11 | 12 | 1. Open a valid module in the editor. 13 | 2. Open the VS Code command palette. 14 | 3. Select `MarkLogic: Eval JS` or `MarkLogic: Eval XQuery` - depending on the type of module. 15 | 16 | Evaluation results will apper in the `MLXPRS: RESULTS` tab in the bottom panel, or open in a new editor tab - depending on the value of the `Marklogic: Results In Editor Tab` setting. 17 | 18 | ### Configuration Override for Module Evaluation 19 | 20 | You can override your VS Code configured settings by using a block comment as the first language token 21 | in a JavaScript or XQuery query. The comment should conform to the following: 22 | 23 | - First line includes the string `mlxprs:settings` 24 | - The rest of the comment is valid JSON 25 | - Includes at least one of the following keys: `host`, `port`, `user`, `pwd`, `contentDb`, `modulesDb`, `authType`, `ssl`, `pathToCa` 26 | - The corresponding value should be of the right type for the configuration (number for `port`, boolean for `ssl`, string otherwise) 27 | 28 | The values defined in the JSON will override VS Code's MarkLogic client configuration. 29 | 30 | For example: 31 | 32 | ```js 33 | /* mlxprs:settings 34 | { 35 | "host": "my-test-host", 36 | "port": 8079, 37 | "contentDb": "unit-test-database", 38 | "note": "These settings are for testing only" 39 | } 40 | */ 41 | 'use strict'; 42 | cts.doc('/my-testing-doc.json'); 43 | ``` 44 | 45 | or: 46 | 47 | ```xquery 48 | (: mlxprs:settings 49 | { 50 | "host": "my-test-host", 51 | "contentDb": "unit-test-database", 52 | "modulesDb": "unit-test-MODULES", 53 | "user": "unit-tester", 54 | "pwd": "red,green,refactor", 55 | "note": "These settings are for testing only" 56 | } 57 | :) 58 | xquery version "1.0-ml"; 59 | fn:doc('/my-testing-doc.json') 60 | ``` 61 | 62 | When this query runs, it will use the host, port, and `contentDb` specified in the comment, along with the VS Code configuration parameters for the rest of the MarkLogic client definition. (The `note` will be ignored.) Other queries in other editor tabs will not be affected. 63 | 64 | **Note: This configuration override is only applied when using one of the "MarkLogic: Eval " commands. 65 | -------------------------------------------------------------------------------- /docs/query-and-script-support/query-and-script-support.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Executing Queries & Scripts 4 | nav_order: 6 5 | has_children: true 6 | permalink: /docs/query-and-script-support 7 | --- 8 | 9 | Executing Queries & Scripts -------------------------------------------------------------------------------- /docs/serverStatusView.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Server Status View 4 | nav_order: 3 5 | --- 6 | 7 | 8 | ### Server Status View 9 | 10 | MLXPRS includes an icon ( 11 | 12 | ) in the VSCode activity bar, which VSCode displays by default on the left side of the 13 | VSCode window. When selected, an explorer view is shown, which can provide information 14 | about the currently configured MarkLogic server. 15 | 16 | The first time the Server Status View is displayed, the MarkLogic server is queried for 17 | a list of configured databases and app servers, as well as a list of app servers that 18 | are currently in "connected" mode - see 19 | [Attach - Attach & step through remote requests](debugging-support/remoteRequests.html) 20 | for more information. Then, the view and lists are updated anytime there is a change to 21 | 'marklogic' configuration values. Finally, you can also request a refresh of a specific 22 | list by clicking on the list header (Databases, App-Servers, Debug App Servers). 23 | 24 | 25 | ### Server Databases & App Servers 26 | 27 | The top half of the MarkLogic Server Explorer is the MarkLogic Server Configuration. 28 | This section displays a list of databases and app servers configured in the MarkLogic 29 | server. 30 | 31 | You can click on any of databases and app servers shown in this section to open the 32 | MarkLogic Admin page for that resource. 33 | 34 | 35 | ### App Server Debug Configuration 36 | 37 | The bottom half of the MarkLogic Server Explorer is the MarkLogic App Server Debug 38 | Status. This section displays a list of App Servers that are currently in "connected" 39 | mode. -------------------------------------------------------------------------------- /docs/testing-support/runningMarkLogicUnitTests.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Running marklogic-unit-test modules 4 | nav_order: 1 5 | parent: Testing Support 6 | --- 7 | 8 | ### Run marklogic-unit-test module 9 | 10 | This plugin provides a convenient method for running a [marklogic-unit-test module](https://marklogic-community.github.io/marklogic-unit-test/) within your MarkLogic server. To get started, your test suites and files must be organized under a "src/test/ml-modules/root/test/suites" directory. See this [ml-gradle sample project](https://github.com/marklogic/ml-gradle/tree/master/examples/unit-test-project) for an example of how to setup the project to use marklogic-unit-test. Additionally, you need to set the `Marklogic: Test Port` setting to the port number of the App Server that can run your unit tests. Finally, to run a test file: 11 | 12 | 1. In an editor tab, open the test file that you wish to be executed. 13 | 2. Open the VS Code command palette. 14 | 3. Select `MarkLogic: Run marklogic-unit-test Module` from the list. 15 | 16 | The results of the tests will appear in the `MLXPRS: RESULTS` tab in the bottom panel. 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/testing-support/testing-support.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Testing Support 4 | nav_order: 5 5 | has_children: true 6 | permalink: /docs/testing-support 7 | --- 8 | 9 | Testing Support -------------------------------------------------------------------------------- /images/ProgressMarkLogic_PrimaryLogo_StackedAlternate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marklogic/mlxprs/2be5e05869cd0b820ddd16268196f549a423cb3e/images/ProgressMarkLogic_PrimaryLogo_StackedAlternate.png -------------------------------------------------------------------------------- /images/attach_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marklogic/mlxprs/2be5e05869cd0b820ddd16268196f549a423cb3e/images/attach_screenshot.png -------------------------------------------------------------------------------- /media/Progress_PrimarySymbol.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/completionTypes.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | class MarkLogicFnDocsObject { 20 | name: string; 21 | prefix: string; 22 | summary: string; 23 | return: string; 24 | example: string[]; 25 | params: MarkLogicParamsObject[] = []; 26 | 27 | constructor(o: any) { 28 | this.name = o.name; 29 | this.prefix = o.prefix; 30 | this.summary = o.summary; 31 | this.return = o.return; 32 | this.example = o.example || []; 33 | this.params = o.params || []; 34 | } 35 | } 36 | 37 | interface MarkLogicParamsObject { 38 | name: string; 39 | type: string; 40 | description: string; 41 | optional?: boolean; 42 | } 43 | 44 | export { 45 | MarkLogicFnDocsObject, MarkLogicParamsObject 46 | }; 47 | -------------------------------------------------------------------------------- /server/completionsSjs.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | import { 20 | CompletionItem, CompletionItemKind 21 | } from 'vscode-languageserver'; 22 | import { 23 | MarkLogicFnDocsObject, MarkLogicParamsObject 24 | } from './completionTypes'; 25 | 26 | export type contentType = { 27 | javascript: object, 28 | xquery: object 29 | } 30 | import hints = require('./etc/marklogic-hint-docs.json'); 31 | const sjsHints = (hints as contentType).javascript; 32 | 33 | const allMlSjsNamespaces: CompletionItem[] = Object.keys(sjsHints).map(ns => { 34 | const ci: CompletionItem = { 35 | label: ns, 36 | kind: CompletionItemKind.Class, 37 | data: ns + '.namespace' 38 | }; 39 | return ci; 40 | }); 41 | 42 | function buildFullFunctionSignature(docObject: MarkLogicFnDocsObject): string { 43 | const neededParams: MarkLogicParamsObject[] = docObject.params.filter(p => { 44 | return p.optional !== true; 45 | }); 46 | const optionParams: MarkLogicParamsObject[] = docObject.params.filter(p => { 47 | return p.optional === true; 48 | }); 49 | const neededParamsString = neededParams.map(p => { 50 | return `${p.name} <${p.type}>`; 51 | }).join(',\n\t'); 52 | const optionParamsString = optionParams.map(p => { 53 | return `[${p.name} <${p.type}>]`; 54 | }).join(',\n\t'); 55 | let middleComma = ''; if (neededParams.length > 0 && optionParams.length > 0) middleComma = ',\n\t'; 56 | const nothing: string = docObject.params.length ? '\n\t' : ''; 57 | return `${docObject.prefix}:${docObject.name}(${nothing}${neededParamsString}${middleComma}${optionParamsString}) 58 | as ${docObject.return}`; 59 | } 60 | 61 | function buildFunctionCompletion(docObject: MarkLogicFnDocsObject): string { 62 | const neededParams: MarkLogicParamsObject[] = docObject.params.filter(p => { 63 | return p.optional !== true; 64 | }); 65 | const optionParams: MarkLogicParamsObject[] = docObject.params.filter(p => { 66 | return p.optional === true; 67 | }); 68 | const neededParamsString = neededParams.map(p => { 69 | return `${p.name}`; 70 | }).join(', '); 71 | const optionParamsString = optionParams.map(p => { 72 | return `[${p.name}]`; 73 | }).join(', '); 74 | let middleComma = ''; if (neededParams.length > 0 && optionParams.length > 0) middleComma = ', '; 75 | return `${docObject.name}(${neededParamsString}${middleComma}${optionParamsString})`; 76 | } 77 | 78 | function mlFnDoc2CompletionItem(docObject: MarkLogicFnDocsObject): CompletionItem { 79 | const nssep = '.'; 80 | const completionItem: CompletionItem = { 81 | label: `${docObject.prefix}${nssep}${docObject.name}()`, 82 | kind: CompletionItemKind.Function, 83 | documentation: docObject.summary, 84 | detail: buildFullFunctionSignature(docObject), 85 | insertText: buildFunctionCompletion(docObject), 86 | data: docObject 87 | }; 88 | return completionItem; 89 | } 90 | 91 | function allMlSjsFunctions(namespace: string): CompletionItem[] { 92 | const theseHints: MarkLogicFnDocsObject[] = sjsHints[namespace] || []; 93 | return [].concat( 94 | ...Object.keys(theseHints).map(fn => { 95 | const hint: MarkLogicFnDocsObject = new MarkLogicFnDocsObject(theseHints[fn]); 96 | if (hint.return !== null) { 97 | const ci: CompletionItem = mlFnDoc2CompletionItem(hint); 98 | return ci; 99 | } else return { label: 'dep' }; 100 | }) 101 | ).filter((h: CompletionItem) => { 102 | return h.label !== 'dep'; 103 | }); 104 | } 105 | 106 | export { 107 | allMlSjsNamespaces, allMlSjsFunctions 108 | }; 109 | -------------------------------------------------------------------------------- /server/completionsXqy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | import { 20 | CompletionItem, CompletionItemKind 21 | } from 'vscode-languageserver'; 22 | import { 23 | MarkLogicFnDocsObject, MarkLogicParamsObject 24 | } from './completionTypes'; 25 | 26 | export type contentType = { 27 | javascript: object, 28 | xquery: object 29 | } 30 | import hints = require('./etc/marklogic-hint-docs.json'); 31 | const xqyHints = (hints as contentType).xquery; 32 | 33 | 34 | const allMlXqyNamespaces: CompletionItem[] = Object.keys(xqyHints).map((ns) => { 35 | const ci: CompletionItem = { 36 | label: ns, 37 | kind: CompletionItemKind.Class, 38 | data: ns + '.namespace' 39 | }; 40 | return ci; 41 | }); 42 | 43 | function buildFunctionCompletion(docObject: MarkLogicFnDocsObject): string { 44 | const neededParams: MarkLogicParamsObject[] = docObject.params.filter(p => { 45 | return p.optional !== true; 46 | }); 47 | const optionParams: MarkLogicParamsObject[] = docObject.params.filter(p => { 48 | return p.optional === true; 49 | }); 50 | const neededParamsString = neededParams.map(p => { 51 | return '$' + p.name; 52 | }).join(', '); 53 | const optionParamsString = optionParams.map(p => { 54 | return '[$' + p.name + ']'; 55 | }).join(', '); 56 | let middleComma = ''; if (neededParams.length > 0 && optionParams.length > 0) middleComma = ', '; 57 | return `${docObject.name}(${neededParamsString}${middleComma}${optionParamsString})`; 58 | } 59 | 60 | function buildFullFunctionSignature(docObject: MarkLogicFnDocsObject): string { 61 | const neededParams: MarkLogicParamsObject[] = docObject.params.filter(p => { 62 | return p.optional !== true; 63 | }); 64 | const optionParams: MarkLogicParamsObject[] = docObject.params.filter(p => { 65 | return p.optional === true; 66 | }); 67 | const neededParamsString = neededParams.map(p => { 68 | return '$' + p.name + ' as ' + p.type; 69 | }).join(',\n\t'); 70 | const optionParamsString = optionParams.map(p => { 71 | return '[$' + p.name + ' as ' + p.type + ']'; 72 | }).join(',\n\t'); 73 | let middleComma = ''; if (neededParams.length > 0 && optionParams.length > 0) middleComma = ',\n\t'; 74 | const nothing: string = docObject.params.length ? '\n\t' : ''; 75 | return `${docObject.prefix}:${docObject.name}(${nothing}${neededParamsString}${middleComma}${optionParamsString}) 76 | as ${docObject.return}`; 77 | } 78 | 79 | 80 | function mlFnDoc2CompletionItem(docObject: MarkLogicFnDocsObject): CompletionItem { 81 | const nssep = ':'; 82 | const completionItem: CompletionItem = { 83 | label: `${docObject.prefix}${nssep}${docObject.name}()`, 84 | kind: CompletionItemKind.Function, 85 | documentation: docObject.summary, 86 | detail: buildFullFunctionSignature(docObject), 87 | insertText: buildFunctionCompletion(docObject), 88 | data: docObject 89 | }; 90 | return completionItem; 91 | } 92 | 93 | function allMlXqyFunctions(namespace: string): CompletionItem[] { 94 | const theseHints: MarkLogicFnDocsObject[] = xqyHints[namespace] || []; 95 | return [].concat( 96 | ...Object.keys(theseHints).map((fn) => { 97 | const hint: MarkLogicFnDocsObject = new MarkLogicFnDocsObject(theseHints[fn]); 98 | if (hint.return !== null) { 99 | const ci: CompletionItem = mlFnDoc2CompletionItem(hint); 100 | return ci; 101 | } else return { label: 'dep' }; 102 | }) 103 | ).filter((h: CompletionItem) => { 104 | return h.label !== 'dep'; 105 | }); 106 | } 107 | 108 | export { 109 | allMlXqyNamespaces, allMlXqyFunctions 110 | }; 111 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mlxprs-languageserver", 3 | "displayName": "mlxprs-languageserver", 4 | "description": "Language Server for XQuery and SJS", 5 | "version": "3.6.2", 6 | "publisher": "mlxprs", 7 | "repository": "https://github.com/mikrovvelle/mlxprs", 8 | "license": "Apache-2.0", 9 | "engines": { 10 | "vscode": "^1.50.0" 11 | }, 12 | "devDependencies": { 13 | "@types/glob": "8.1.0", 14 | "@types/mocha": "10.0.1", 15 | "@types/vscode": "1.77.0", 16 | "copyfiles": "2.4.1", 17 | "mem": "9.0.2", 18 | "mocha": "10.2.0", 19 | "os-locale": "6.0.2", 20 | "vscode-languageserver": "7.0.0", 21 | "vscode-languageserver-textdocument": "1.0.8", 22 | "@vscode/test-electron": "2.3.0" 23 | }, 24 | "scripts": { 25 | "copy-files": "copyfiles -ufV etc/*.json dist/etc/", 26 | "compile": "tsc -b test/tsconfig.json", 27 | "watch": "tsc -w -b test/tsconfig.json", 28 | "pretest": "npm run compile", 29 | "test": "node ./dist/test/runTest.js" 30 | } 31 | } -------------------------------------------------------------------------------- /server/server.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict'; 18 | 19 | import { 20 | IPCMessageReader, IPCMessageWriter, 21 | createConnection, Connection, 22 | TextDocuments, 23 | TextDocumentPositionParams, 24 | CompletionItem, CompletionItemKind, InitializeParams, InitializeResult, 25 | TextDocumentSyncKind 26 | } from 'vscode-languageserver/node'; 27 | import { TextDocument } from 'vscode-languageserver-textdocument'; 28 | 29 | import { 30 | allMlSjsFunctions, allMlSjsNamespaces 31 | } from './completionsSjs'; 32 | import { 33 | allMlXqyFunctions, allMlXqyNamespaces 34 | } from './completionsXqy'; 35 | 36 | const connection: Connection = createConnection(new IPCMessageReader(process), new IPCMessageWriter(process)); 37 | 38 | const documents: TextDocuments = new TextDocuments(TextDocument); 39 | documents.listen(connection); 40 | 41 | connection.onInitialize((): InitializeResult => { 42 | return { 43 | capabilities: { 44 | // Tell the client that the server works in FULL text document sync mode 45 | textDocumentSync: TextDocumentSyncKind.Full, 46 | // Tell the client that the server supports code complete 47 | completionProvider: { 48 | resolveProvider: true, 49 | triggerCharacters: [':', '$', '.'] 50 | }, 51 | definitionProvider: false 52 | } 53 | }; 54 | }); 55 | 56 | connection.listen(); 57 | const b = /\b/g; // barrier 58 | const xw = /[\w\d-]+/g; // xquery word 59 | const xv = /[$\w\d-]/g; // variable 60 | 61 | const jwv = /[\w\d]+/g; // JS word or variable 62 | 63 | function getTheseTokens(document: TextDocument, offset: number): string[] { 64 | const preceding = document.getText().slice(0, offset); 65 | const thisLine = preceding.slice(preceding.lastIndexOf('\n')); 66 | const theseTokens: string[] = thisLine.split(b); 67 | return theseTokens; 68 | } 69 | 70 | function completeXQuery(document: TextDocument, offset: number): CompletionItem[] { 71 | let allCompletions: CompletionItem[] = []; 72 | const theseTokens = getTheseTokens(document, offset); 73 | 74 | // shortcircuit: don't complete on dot in XQuery 75 | if (theseTokens.slice(-1)[0] === '.') { 76 | return allCompletions; 77 | } else if (theseTokens.slice(-1)[0] === ':' && theseTokens.slice(-2)[0].match(jwv)) { 78 | const namespace: string = theseTokens.slice(-2)[0]; 79 | allCompletions = allCompletions.concat(allMlXqyFunctions(namespace)); 80 | } else if (theseTokens.slice(-2)[0].match(xw) && theseTokens.slice(-1)[0] === ':') { 81 | const namespace: string = theseTokens.slice(-3)[0]; 82 | allCompletions = allCompletions.concat(allMlXqyFunctions(namespace)); 83 | } else if (allCompletions.length === 0 || allCompletions[0].kind === CompletionItemKind.Class) { 84 | allCompletions = allCompletions.concat(allMlXqyNamespaces); 85 | } 86 | 87 | return allCompletions; 88 | } 89 | 90 | function completeSJS(document: TextDocument, offset: number): CompletionItem[] { 91 | let allCompletions: CompletionItem[] = []; 92 | const theseTokens = getTheseTokens(document, offset); 93 | 94 | // shortcircuit: don't complete on colon in Javascript 95 | if (theseTokens.slice(-1)[0] === ':') { 96 | return allCompletions; 97 | } 98 | 99 | if (theseTokens.slice(-1)[0] === '.' && theseTokens.slice(-2)[0].match(jwv)) { 100 | const namespace: string = theseTokens.slice(-2)[0]; 101 | allCompletions = allCompletions.concat(allMlSjsFunctions(namespace)); 102 | } else if (theseTokens.slice(-2)[0].match(jwv) && theseTokens.slice(-1)[0] === '.') { 103 | const namespace: string = theseTokens.slice(-3)[0]; 104 | allCompletions = allCompletions.concat(allMlSjsFunctions(namespace)); 105 | } else if (allCompletions.length === 0 || allCompletions[0].kind === CompletionItemKind.Class) { 106 | allCompletions = allCompletions.concat(allMlSjsNamespaces); 107 | } 108 | 109 | return allCompletions; 110 | } 111 | 112 | 113 | connection.onCompletion((textDocumentPositionParams: TextDocumentPositionParams): CompletionItem[] => { 114 | const document = documents.get(textDocumentPositionParams.textDocument.uri); 115 | const lang = document.languageId || 'javascript'; 116 | const offset = document.offsetAt(textDocumentPositionParams.position); 117 | 118 | return { 119 | 'xquery-ml': completeXQuery, 120 | 'javascript': completeSJS 121 | }[lang](document, offset); 122 | }); 123 | 124 | 125 | connection.onCompletionResolve((item: CompletionItem): CompletionItem => { 126 | return item; 127 | }); 128 | 129 | -------------------------------------------------------------------------------- /server/test/runTest.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as path from 'path'; 18 | 19 | import { runTests } from '@vscode/test-electron'; 20 | 21 | async function main(): Promise { 22 | try { 23 | // The folder containing the Extension Manifest package.json 24 | // Passed to `--extensionDevelopmentPath` 25 | console.debug('Starting to run tests'); 26 | const extensionDevelopmentPath = path.resolve(__dirname, '../../../../'); 27 | 28 | // The path to the extension test script 29 | // Passed to --extensionTestsPath 30 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 31 | 32 | // Download VS Code, unzip it and run the integration test 33 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 34 | } catch (err) { 35 | console.error('Failed to run tests'); 36 | process.exit(1); 37 | } 38 | } 39 | 40 | main(); 41 | -------------------------------------------------------------------------------- /server/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as path from 'path'; 18 | import * as Mocha from 'mocha'; 19 | import * as glob from 'glob'; 20 | 21 | export function run(): Promise { 22 | // Create the mocha test 23 | const mocha = new Mocha({ 24 | ui: 'tdd', 25 | color: true 26 | }); 27 | 28 | const testsRoot = path.resolve(__dirname, '..'); 29 | 30 | return new Promise((c, e) => { 31 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 32 | if (err) { 33 | return e(err); 34 | } 35 | 36 | // Add files to the test suite 37 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 38 | 39 | try { 40 | // Run the mocha test 41 | mocha.run(failures => { 42 | if (failures > 0) { 43 | e(new Error(`${failures} tests failed.`)); 44 | } else { 45 | c(); 46 | } 47 | }); 48 | } catch (err) { 49 | e(err); 50 | } 51 | }); 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /server/test/suite/server.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as assert from 'assert'; 18 | import { after, before } from 'mocha'; 19 | 20 | // You can import and use all API from the 'vscode' module 21 | // as well as import your extension to test it 22 | import * as completionsXqy from '../../completionsXqy'; 23 | import * as completionsSjs from '../../completionsSjs'; 24 | 25 | // Defines a Mocha test suite to group tests of similar kind together 26 | suite('Extension Tests', () => { 27 | 28 | before(() => { 29 | console.debug('starting server tests!'); 30 | }); 31 | 32 | after(() => { 33 | console.debug('All server tests done!'); 34 | }); 35 | 36 | // Defines a Mocha unit test 37 | test('Something 1', () => { 38 | assert.equal(-1, [1, 2, 3].indexOf(5)); 39 | assert.equal(-1, [1, 2, 3].indexOf(0)); 40 | }); 41 | 42 | test('getting MarkLogic namespace hints (sanity check)', () => { 43 | const allXqN = completionsXqy.allMlXqyNamespaces; 44 | assert.notEqual(allXqN, 0); 45 | const allSjsN = completionsSjs.allMlSjsNamespaces; 46 | assert.notEqual(allSjsN, 0); 47 | }); 48 | 49 | test('getting MarkLogic function hints (sanity check)', () => { 50 | const AllXqF = completionsXqy.allMlXqyFunctions; 51 | assert.ok(AllXqF); 52 | const AllSjsF = completionsSjs.allMlSjsFunctions; 53 | assert.ok(AllSjsF); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /server/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "../out", 6 | "lib": [ "es6" ], 7 | "sourceMap": true, 8 | "rootDir": "..", 9 | 10 | // "noUnusedLocals": true, 11 | // "noUnusedParameters": true, 12 | // "noImplicitAny": true, 13 | "noImplicitReturns": true 14 | }, 15 | "exclude": [ 16 | "node_modules", 17 | ".vscode-test" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "dist", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": ".", 11 | "resolveJsonModule": true, 12 | "noImplicitReturns": true 13 | // "noUnusedLocals": true, 14 | // "noUnusedParameters": true, 15 | // "noImplicitAny": true, 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } -------------------------------------------------------------------------------- /server/webpack.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable @typescript-eslint/no-var-requires */ 18 | //@ts-check 19 | 20 | 'use strict'; 21 | 22 | const withDefaults = require('../shared.webpack.config'); 23 | const path = require('path'); 24 | 25 | module.exports = withDefaults({ 26 | context: path.join(__dirname), 27 | entry: { 28 | extension: './server.ts', 29 | }, 30 | output: { 31 | filename: 'server.js', 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /shared.webpack.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable @typescript-eslint/no-var-requires */ 18 | //@ts-check 19 | /** @typedef {import('webpack').Configuration} WebpackConfig **/ 20 | 21 | 'use strict' 22 | 23 | const path = require('path') 24 | const merge = require('merge-options') 25 | 26 | // eslint-disable-next-line @typescript-eslint/explicit-function-return-type 27 | module.exports = function withDefaults(/**@type WebpackConfig*/extConfig) { 28 | 29 | /** @type WebpackConfig */ 30 | const defaultConfig = { 31 | mode: 'none', 32 | target: 'node', // vscode extensions run in a Node.js-context 33 | // 📖 -> https://webpack.js.org/configuration/node/ 34 | node: { 35 | __dirname: false 36 | }, 37 | resolve: { 38 | mainFields: ['module', 'main'], 39 | extensions: ['.ts', '.js'] 40 | }, 41 | module: { 42 | rules: [{ 43 | test: /\.ts$/, 44 | exclude: /node_modules/, 45 | use: [{ 46 | loader: 'ts-loader', 47 | }] 48 | }] 49 | }, 50 | devtool: 'source-map', 51 | externals: { 52 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. 53 | // Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 54 | }, 55 | output: { 56 | // the bundle is stored in the 'dist' folder (check package.json) 57 | // 📖 -> https://webpack.js.org/configuration/output/ 58 | filename: '[name].js', 59 | path: path.join(extConfig.context, 'dist'), 60 | libraryTarget: 'commonjs', 61 | }, 62 | } 63 | 64 | return merge(defaultConfig, extConfig) 65 | } 66 | -------------------------------------------------------------------------------- /snippets/snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "attribute": { 3 | "prefix": "attribute", 4 | "body": "attribute ${1:name} { ${2:()} \\}", 5 | "description": "constructed attribute (inline)", 6 | "scope": "source.xquery-ml" 7 | }, 8 | "element": { 9 | "prefix": "element", 10 | "body": "element ${1:name} { ${2:()} \\}", 11 | "description": "constructed element (inline)", 12 | "scope": "source.xquery-ml" 13 | }, 14 | "element1": { 15 | "prefix": "element", 16 | "body": "element ${1:name} {\n\t${2:()}\n\\}", 17 | "description": "constructed element", 18 | "scope": "source.xquery-ml" 19 | }, 20 | "if": { 21 | "prefix": "if", 22 | "body": "if (${1:expression}) then\n\t${2:()}\nelse\n\t${3:()}", 23 | "description": "if then else", 24 | "scope": "source.xquery-ml" 25 | }, 26 | "try": { 27 | "prefix": "try", 28 | "body": "try {\n\t${1:expression}\n} catch (${2:exception}) {\n\t${3:handler}\n\\}", 29 | "description": "try-catch expression", 30 | "scope": "source.xquery-ml" 31 | }, 32 | "module": { 33 | "prefix": "module", 34 | "body": "xquery version \"1.0-ml\";\n\nmodule namespace ${1:ns} = \"${2:http://namespace-uri}\";\n\ndeclare option xdmp:mapping \"false\";\n\n${3:(: Tab to me to start your module! :)}\n", 35 | "description": "Barebones XQuery Module Template", 36 | "scope": "source.xquery-ml" 37 | }, 38 | "ns": { 39 | "prefix": "ns", 40 | "body": "declare namespace ${1:ns} = \"${2:http://namespace-uri}\";", 41 | "description": "namespace declaration", 42 | "scope": "source.xquery-ml" 43 | }, 44 | "switch": { 45 | "prefix": "switch", 46 | "body": "switch (${1:expression})\n\tcase ${2:expression} return\n\t\t${3:expression}\n\tdefault return\n\t\t${4:expression}", 47 | "description": "switch statement", 48 | "scope": "source.xquery-ml" 49 | }, 50 | "type": { 51 | "prefix": "type", 52 | "body": "typeswitch(${1:expression})\n\tcase ${2:expression} return\n\t\t${3:expression}\n\tdefault return\n\t\t${4:expression}", 53 | "description": "typeswitch", 54 | "scope": "source.xquery-ml" 55 | }, 56 | "var": { 57 | "prefix": "var", 58 | "body": "declare variable \\$${1:x} := ${2:()};", 59 | "description": "variable declaration", 60 | "scope": "source.xquery-ml" 61 | }, 62 | "debug": { 63 | "prefix": "debug", 64 | "body": "xdmp:log(${0}, \"debug\")", 65 | "description": "Debug xdmp:log …", 66 | "scope": "source.xquery-ml" 67 | }, 68 | "log": { 69 | "prefix": "log", 70 | "body": "xdmp:log(${0})", 71 | "description": "xdmp:log …", 72 | "scope": "source.xquery-ml" 73 | }, 74 | "xquery": { 75 | "prefix": "xquery", 76 | "body": "xquery version \"1.0-ml\";", 77 | "description": "version declaration", 78 | "scope": "source.xquery-ml" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /test-app/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.js] 13 | indent_size = 4 14 | 15 | [*.json] 16 | indent_size = 4 17 | 18 | [*.ts] 19 | indent_size = 4 20 | 21 | [*.md] 22 | trim_trailing_whitespace = false 23 | -------------------------------------------------------------------------------- /test-app/.eslintignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marklogic/mlxprs/2be5e05869cd0b820ddd16268196f549a423cb3e/test-app/.eslintignore -------------------------------------------------------------------------------- /test-app/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "extends": "plugin:@typescript-eslint/recommended", 7 | "globals": { 8 | "Atomics": "readonly", 9 | "SharedArrayBuffer": "readonly" 10 | }, 11 | "parser": "@typescript-eslint/parser", 12 | "plugins": [ 13 | "@typescript-eslint" 14 | ], 15 | "parserOptions": { 16 | "ecmaVersion": 2018, 17 | "sourceType": "module" 18 | }, 19 | "overrides": [ 20 | { 21 | "files": "**/*.ts", 22 | "excludedFiles": [ 23 | "dist/**/*.js", 24 | "out/**/*.js" 25 | ] 26 | } 27 | ], 28 | "rules": { 29 | "@typescript-eslint/no-var-requires": "off", 30 | "indent": [ 31 | "error", 32 | 4 33 | ], 34 | "linebreak-style": [ 35 | "error", 36 | "unix" 37 | ], 38 | "quotes": [ 39 | "error", 40 | "single" 41 | ], 42 | "semi": [ 43 | "error", 44 | "always" 45 | ], 46 | "arrow-spacing": [ 47 | "error", 48 | { 49 | "before": true, 50 | "after": true 51 | } 52 | ], 53 | "space-before-blocks": [ 54 | "error", 55 | "always" 56 | ], 57 | "space-before-function-paren": [ 58 | "error", 59 | { 60 | "named": "never", 61 | "asyncArrow": "always" 62 | } 63 | ], 64 | "space-in-parens": [ 65 | "error", 66 | "never" 67 | ], 68 | "object-curly-spacing": [ 69 | "error", 70 | "always" 71 | ], 72 | "keyword-spacing": [ 73 | "error", 74 | { 75 | "before": true, 76 | "after": true 77 | } 78 | ], 79 | "comma-spacing": [ 80 | "error", 81 | { 82 | "before": false, 83 | "after": true 84 | } 85 | ], 86 | "key-spacing": [ 87 | "error", 88 | { 89 | "beforeColon": false, 90 | "afterColon": true 91 | } 92 | ], 93 | "space-infix-ops": [ 94 | "error" 95 | ], 96 | "no-var": "error", 97 | "array-bracket-spacing": "error", 98 | "block-spacing": "error", 99 | "brace-style": [ 100 | "error", 101 | "1tbs", 102 | { 103 | "allowSingleLine": false 104 | } 105 | ], 106 | "curly": [ 107 | "error", 108 | "multi-line" 109 | ], 110 | "func-call-spacing": "error", 111 | "no-trailing-spaces": "error", 112 | "no-console": [ 113 | "error", 114 | { 115 | "allow": [ 116 | "warn", 117 | "error", 118 | "debug" 119 | ] 120 | } 121 | ], 122 | "eqeqeq": "error" 123 | } 124 | } -------------------------------------------------------------------------------- /test-app/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "ml-jsdebugger", 9 | "request": "launch", 10 | "name": "Evaluate Current JavaScript Module", 11 | "root": "${workspaceFolder}/src/main/ml-modules/root", 12 | // "debugServer": 4711 13 | }, 14 | { 15 | "type": "ml-jsdebugger", 16 | "request": "launch", 17 | "name": "Evaluate Specific JavaScript Module", 18 | "root": "${workspaceFolder}/src/main/ml-modules/root", 19 | "program": "/Users/pbarber/Documents/workspaces/engineering/mlxprsStuff/mlxprsSampleProject/src/main/ml-modules/root/javascript/launch.sjs", 20 | // "debugServer": 4711 21 | }, 22 | { 23 | "type": "ml-jsdebugger", 24 | "request": "attach", 25 | "name": "Attach to Remote JavaScript Request", 26 | "root": "${workspaceFolder}", 27 | "debugServerName": "mlxprs-test-test", 28 | // "debugServer": 4711 29 | }, 30 | { 31 | "type": "xquery-ml", 32 | "request": "launch", 33 | "name": "Evaluate Current XQuery Module", 34 | "root": "${workspaceFolder}/src/main/ml-modules/root", 35 | // "debugServer": 4712 36 | }, 37 | { 38 | "type": "xquery-ml", 39 | "request": "launch", 40 | "name": "Evaluate Specific XQuery Module", 41 | "root": "${workspaceFolder}/src/main/ml-modules/root", 42 | "program": "/Users/pbarber/Documents/workspaces/engineering/mlxprsStuff/mlxprsSampleProject/src/main/ml-modules/root/xquery/longTest.xqy" 43 | // "debugServer": 4712 44 | }, 45 | { 46 | "type": "xquery-ml", 47 | "request": "attach", 48 | "name": "Attach to Remote XQuery Request", 49 | "root": "${workspaceFolder}/src/main/ml-modules/root", 50 | // "debugServer": 4712 51 | } 52 | ] 53 | } -------------------------------------------------------------------------------- /test-app/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.configuration.updateBuildConfiguration": "automatic", 3 | "java.compile.nullAnalysis.mode": "disabled", 4 | "marklogic.documentsDb": "mlxprs-test-content", 5 | "marklogic.modulesDb": "mlxprs-test-modules", 6 | "marklogic.rejectUnauthorized": false, 7 | "marklogic.resultsInEditorTab": false, 8 | // Use these for non-proxy testing 9 | "marklogic.host": "localhost", 10 | "marklogic.ssl": false, 11 | "marklogic.authType": "BASIC", 12 | "marklogic.port": 8055, 13 | "marklogic.restBasePath": "", 14 | "marklogic.managePort": 8059, 15 | "marklogic.manageBasePath": "", 16 | "marklogic.testPort": 8054, 17 | "marklogic.testBasePath": "", 18 | "marklogic.adminPort": 8001, 19 | "marklogic.adminBasePath": "", 20 | // Use these for the reverse proxy and basePath testing 21 | // "marklogic.host": "localhost", 22 | // "marklogic.ssl": false, 23 | // "marklogic.authType": "BASIC", 24 | // "marklogic.port": 8020, 25 | // "marklogic.restBasePath": "/mlxprs/rest", 26 | // "marklogic.managePort": 8020, 27 | // "marklogic.manageBasePath": "/mlxprs/manage", 28 | // "marklogic.testPort": 8020, 29 | // "marklogic.testBasePath": "/mlxprs/test", 30 | // "marklogic.adminPort": 8001, 31 | // "marklogic.adminBasePath": "", 32 | // Use these for MarkLogic cloud testing 33 | // "marklogic.host": "support.test.marklogic.cloud", 34 | // "marklogic.ssl": true, 35 | // "marklogic.authType": "CLOUD", 36 | // "marklogic.apiKey": "XXXXXXXXX", 37 | // "marklogic.port": 443, 38 | // "marklogic.restBasePath": "/ml/test/marklogic/mlxprs-test", 39 | // "marklogic.managePort": 443, 40 | // "marklogic.manageBasePath": "/ml/test/marklogic/manage", 41 | // "marklogic.testPort": 443, 42 | // "marklogic.testBasePath": "", 43 | // "marklogic.adminPort": 443, 44 | // "marklogic.adminBasePath": "/ml/test/marklogic/0/admin", 45 | } -------------------------------------------------------------------------------- /test-app/build.gradle: -------------------------------------------------------------------------------- 1 | // Only used for setting up the test AppServer in MarkLogic 2 | plugins { 3 | id 'net.saliman.properties' version '1.5.2' 4 | id "com.marklogic.ml-gradle" version "4.5.2" 5 | } 6 | 7 | ext { 8 | def command = new com.marklogic.appdeployer.command.security.GenerateTemporaryCertificateCommand() 9 | command.setTemplateIdOrName("mlxprs-ssl-certificate-template") 10 | command.setCommonName("localhost") 11 | command.setValidFor(365) 12 | mlAppDeployer.commands.add(command) 13 | } 14 | 15 | repositories { 16 | mavenCentral() 17 | } 18 | 19 | dependencies { 20 | mlBundle "com.marklogic:marklogic-unit-test-modules:1.3.0" 21 | } 22 | -------------------------------------------------------------------------------- /test-app/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '1.0' 2 | name: mlxprs 3 | 4 | services: 5 | 6 | marklogic: 7 | image: "progressofficial/marklogic-db:latest" 8 | platform: linux/amd64 9 | environment: 10 | - INSTALL_CONVERTERS=true 11 | - MARKLOGIC_INIT=true 12 | - MARKLOGIC_ADMIN_USERNAME=admin 13 | - MARKLOGIC_ADMIN_PASSWORD=admin 14 | volumes: 15 | - ./docker/marklogic/logs:/var/opt/MarkLogic/Logs 16 | ports: 17 | - 8000-8002:8000-8002 18 | - 8050-8059:8050-8059 19 | -------------------------------------------------------------------------------- /test-app/gradle.properties: -------------------------------------------------------------------------------- 1 | mlAppName=mlxprs-test 2 | 3 | mlRestPort=8055 4 | mlContentForestsPerHost=1 5 | mlTestRestPort=8054 6 | mlModulePaths=src/main/ml-modules,src/test/ml-modules 7 | 8 | # Local config 9 | mlRestAuthentication=basic 10 | mlHost=localhost 11 | mlUsername=admin 12 | mlPassword=changeme-in-gradle-local.properties 13 | 14 | # Cloud config 15 | # In order to deploy this to a MarkLogic Cloud server: 16 | # 1) Create the path for the app-server in the "MARKLOGIC DATABASE SERVICE" pane of the cloud admin page 17 | # => Click the down arrow, and select "Configure HTTP Endpoints" 18 | # => Click the "+" button, choose the app server, change the path or display name if you want, click "Save Changes" 19 | # 2) On the MarkLogic page for the app-server, ML_CLOUD_TOKEN to the External Securities 20 | #mlAuthentication=CLOUD 21 | #mlHost=support.test.marklogic.cloud 22 | #mlAuthentication=cloud 23 | #mlSslHostnameVerifier=ANY 24 | #mlManageBasePath=ml/test/marklogic/manage 25 | #mlAdminBasePath=ml/test/marklogic/0/admin 26 | #mlAppServicesBasePath=ml/test/marklogic/app-services 27 | #mlRestBasePath=ml/test/marklogic/mlxprs-test 28 | #mlCloudApiKey= 29 | -------------------------------------------------------------------------------- /test-app/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marklogic/mlxprs/2be5e05869cd0b820ddd16268196f549a423cb3e/test-app/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /test-app/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /test-app/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /test-app/src/main/ml-bad-schemas/invalid-authors-TDE.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": { 3 | "context": "/Citations/Citation/Article/AuthorList/Author", 4 | "rows": [ 5 | { 6 | "schemaName": "Medical" 7 | } 8 | ], 9 | 10 | "vars":[ 11 | { 12 | "name":"YYYY", 13 | "val":"YYYY.xml" 14 | }, 15 | { 16 | "name":"MLXPRS_TEST_URI", 17 | "val":"/citations.xml" 18 | }, 19 | { 20 | "name":"ZZZZ", 21 | "val":"ZZZZ.xml" 22 | } 23 | ], 24 | "triples":[{ 25 | "subject":{ 26 | "val":"sem:iri($prefix1||'person/'||AuthorList/Author[1]/ForeName||'_'||AuthorList/Author[1]/LastName)"}, 27 | "predicate":{ 28 | "val":"sem:iri(($prefix1||'authored'))"}, 29 | "object":{ 30 | "val":"xs:string(../../Journal/ISSN)"} 31 | } 32 | ] 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test-app/src/main/ml-bad-schemas/invalid-json-TDE.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": 3 | } 4 | -------------------------------------------------------------------------------- /test-app/src/main/ml-bad-schemas/invalid-publications-TDE.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/src/main/ml-bad-schemas/invalid-xml-TDE.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/src/main/ml-config/databases/content-database.json: -------------------------------------------------------------------------------- 1 | { 2 | "database-name": "%%DATABASE%%", 3 | "schema-database": "%%SCHEMAS_DATABASE%%" 4 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-config/databases/schemas-database.json: -------------------------------------------------------------------------------- 1 | { 2 | "database-name": "%%SCHEMAS_DATABASE%%" 3 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-config/security/certificate-templates/test-app-ssl-template.xml: -------------------------------------------------------------------------------- 1 | 2 | mlxprs-ssl-certificate-template 3 | This template is used for manually test the SSL capabilities of MLXPRS. 4 | It is not currently used in automated testing, but that is planned. 5 | rsa 6 | 7 | 8 | 0 9 | 10 | US 11 | VA 12 | Fredericksburg 13 | MarkLogic 14 | Engineering 15 | nobody@marklogic.com 16 | 17 | 18 | -------------------------------------------------------------------------------- /test-app/src/main/ml-config/servers/NoSsl-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "server-type": "http", 3 | "server-name": "mlxprsSample", 4 | "authentication": "basic", 5 | "port": 8056, 6 | "modules-database": "mlxprs-test-modules", 7 | "content-database": "mlxprs-test-content", 8 | "root": "/", 9 | "url-rewriter": "/MarkLogic/rest-api/rewriter.xml", 10 | "error-handler": "/MarkLogic/rest-api/error-handler.xqy" 11 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-config/servers/manage-basic.json: -------------------------------------------------------------------------------- 1 | { 2 | "server-type": "http", 3 | "server-name": "Manage-basic", 4 | "root": "Apps/", 5 | "port": 8059, 6 | "content-database": "App-Services", 7 | "authentication": "basic", 8 | "error-handler": "manage/error-handler.xqy", 9 | "url-rewriter": "/MarkLogic/manage/rewriter.xml", 10 | "rewrite-resolves-globally": true 11 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-config/servers/manage-ssl-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "server-type": "http", 3 | "server-name": "Manage-ssl", 4 | "root": "Apps/", 5 | "port": 8052, 6 | "content-database": "App-Services", 7 | "authentication": "basic", 8 | "error-handler": "manage/error-handler.xqy", 9 | "url-rewriter": "/MarkLogic/manage/rewriter.xml", 10 | "rewrite-resolves-globally": true, 11 | "ssl-certificate-template": "mlxprs-ssl-certificate-template", 12 | "ssl-require-client-certificate": false 13 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-config/servers/rest-api-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "server-name": "%%NAME%%", 3 | "authentication": "basic" 4 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-config/servers/ssl-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "server-type": "http", 3 | "server-name": "mlxprs-ssl-test", 4 | "root": "/", 5 | "port": 8057, 6 | "modules-database": "mlxprs-test-modules", 7 | "content-database": "mlxprs-test-content", 8 | "authentication": "basic", 9 | "error-handler": "/MarkLogic/rest-api/error-handler.xqy", 10 | "url-rewriter": "/MarkLogic/rest-api/rewriter.xml", 11 | "rewrite-resolves-globally": true, 12 | "ssl-certificate-template": "mlxprs-ssl-certificate-template", 13 | "ssl-require-client-certificate": false 14 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-config/servers/test-rest-api-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "server-name": "%%NAME%%-test", 3 | "authentication": "basic" 4 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-data/a.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": "a" 3 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-data/citations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 |
5 | 6 | 61296-004 7 | 8 | 44 9 | 10 | 2022-07-13 11 | 2022 12 | 07 13 | 13 14 | 15 | 16 | 17 | 18 | 19 | 20 | Golby 21 | Pen 22 | 23 | 24 | Bernadzki 25 | Cherianne 26 | 27 | 28 | Canham 29 | Tybie 30 | 31 | 32 | Awton 33 | Finlay 34 | 35 | 36 |
37 |
38 | 39 | 2 40 |
41 | 42 | 64578-0098 43 | 44 | 0 45 | 46 | 2022-05-11 47 | 2022 48 | 05 49 | 11 50 | 51 | 52 | 53 | 54 | 55 | 56 | Tonnesen 57 | Rani 58 | 59 | 60 | Bau 61 | Christiano 62 | 63 | 64 | Pulhoster 65 | Misty 66 | 67 | 68 | Scarsbrick 69 | Fields 70 | 71 | 72 |
73 |
74 | 75 | 3 76 |
77 | 78 | 62598-001 79 | 80 | 5 81 | 82 | 2022-04-11 83 | 2022 84 | 04 85 | 11 86 | 87 | 88 | 89 | 90 | 91 | 92 | Edeler 93 | Appolonia 94 | 95 | 96 | Shoebotham 97 | Taite 98 | 99 | 100 | Cowe 101 | Moria 102 | 103 | 104 | Crispe 105 | Teddie 106 | 107 | 108 |
109 |
110 | 111 | 4 112 |
113 | 114 | 65862-148 115 | 116 | 51 117 | 118 | 2022-06-10 119 | 2022 120 | 06 121 | 10 122 | 123 | 124 | 125 | 126 | 127 | 128 | Wooles 129 | Vivianne 130 | 131 | 132 |
133 |
134 | 135 | 5 136 |
137 | 138 | 55154-4737 139 | 140 | 2 141 | 142 | 2022-07-12 143 | 2022 144 | 07 145 | 12 146 | 147 | 148 | 149 | 150 | 151 | 152 | Humbee 153 | Aida 154 | 155 | 156 | Dunford 157 | Lyman 158 | 159 | 160 |
161 |
162 |
163 | -------------------------------------------------------------------------------- /test-app/src/main/ml-data/collections.properties: -------------------------------------------------------------------------------- 1 | *=sample 2 | -------------------------------------------------------------------------------- /test-app/src/main/ml-data/extraCitations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 |
5 | 6 | 99999-004 7 | 8 | 99 9 | 10 | 2023-07-13 11 | 2023 12 | 07 13 | 13 14 | 15 | 16 | 17 | 18 | 19 | 20 | Bill 21 | Jones 22 | 23 | 24 | Tom 25 | Johnson 26 | 27 | 28 |
29 |
30 |
31 | -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/graphql/authors.json: -------------------------------------------------------------------------------- 1 | {"query": "query Authors { Medical_Authors { ID LastName } }"} -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/javascript/callOptic.sjs: -------------------------------------------------------------------------------- 1 | const op = require('/MarkLogic/optic'); 2 | 3 | op.fromView('Medical', 'Authors') 4 | .where(op.eq(op.col('ID'), 5)) 5 | .select(['LastName', 'ForeName']) 6 | .result(); -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/javascript/launch.sjs: -------------------------------------------------------------------------------- 1 | const { hello } = require('/javascript/library'); 2 | const friend = 'Jehoshaphat'; 3 | const greeting = hello(friend); 4 | console.debug(greeting); 5 | greeting; -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/javascript/library.sjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function hello(friend) { 4 | return 'Hello, ' + friend; 5 | } 6 | 7 | exports.hello = hello; 8 | -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/javascript/random.js: -------------------------------------------------------------------------------- 1 | [ 2 | xdmp.random() 3 | , 4 | fn.head(fn.doc("/citations.xml")) 5 | .xpath("Citations").toArray()[0] 6 | .xpath("Citation").toArray()[0] 7 | .xpath("Article").toArray()[0] 8 | .xpath("AuthorList").toArray()[0] 9 | .xpath("Author").toArray()[0] 10 | .xpath("LastName").toArray() 11 | ] -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/javascript/testJs.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const { collections } = require('/MarkLogic/jsearch') 4 | 5 | const results = collections('sample').documents().result() 6 | console.debug('resultsAAAA') 7 | console.debug(results) 8 | 9 | console.debug('start') 10 | xdmp.log('xdmp') 11 | 12 | const someVar = 'value' 13 | console.error(someVar) 14 | results 15 | -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/javascript/testModule.mjs: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const jsearch = require('/MarkLogic/jsearch') 4 | 5 | const results = jsearch.collections('sample').documents().result() 6 | console.log('resultsAAAA') 7 | console.log(results) 8 | 9 | console.log('start') 10 | xdmp.log('xdmp') 11 | 12 | const someVar = 'value' 13 | console.error(someVar) 14 | results 15 | -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/javascript/testSjs.sjs: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const jsearch = require('/MarkLogic/jsearch') 4 | 5 | const results = jsearch.collections('sample').documents().result() 6 | console.log('asdfasdfsadfsadf') 7 | console.log(results) 8 | 9 | console.log('start') 10 | xdmp.log('xdmp') 11 | 12 | const someVar = 'value' 13 | console.error(someVar) 14 | results 15 | -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/lib/factorial.sjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function factorial(num) { 4 | if (num === 1) { 5 | return 1; 6 | } else { 7 | return num * factorial(num - 1); 8 | } 9 | } 10 | 11 | exports.factorial = factorial; 12 | -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/optic/dslQuery.js: -------------------------------------------------------------------------------- 1 | op.fromView('Medical', 'Authors') 2 | .where(op.eq(op.col('ID'), 5)) 3 | .select(['LastName', 'ForeName']) 4 | -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/optic/query.json: -------------------------------------------------------------------------------- 1 | { 2 | "$optic": { 3 | "ns": "op", 4 | "fn": "operators", 5 | "args": [ 6 | { 7 | "ns": "op", 8 | "fn": "from-view", 9 | "args": [ 10 | "Medical", 11 | "Authors" 12 | ] 13 | } 14 | ] 15 | } 16 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/sparql/some.sparql: -------------------------------------------------------------------------------- 1 | PREFIX authors: SELECT * WHERE { ?s authors:Date ?o } -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/sql/authors.sql: -------------------------------------------------------------------------------- 1 | select * from Medical.Authors 2 | where LastName = 'Golby' 3 | -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/xquery/callOptic.xqy: -------------------------------------------------------------------------------- 1 | xquery version "1.0-ml"; 2 | 3 | import module namespace op="http://marklogic.com/optic" at "/MarkLogic/optic.xqy"; 4 | 5 | op:from-view('Medical', 'Authors') 6 | => op:select(('LastName', 'ForeName')) 7 | => op:order-by('LastName') 8 | => op:result() -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/xquery/eval.xqy: -------------------------------------------------------------------------------- 1 | world -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/xquery/launch.xqy: -------------------------------------------------------------------------------- 1 | xquery version "1.0-ml"; 2 | 3 | 4 | import module namespace hw = "helloworld" at "/xquery/library.xqy"; 5 | 6 | let $_ := xdmp:log("running launch.xqy") 7 | let $response := 8 | let $response := 9 | 10 | hw:helloworld() 11 | 12 | 13 | 14 | return $response 15 | let $_ := ( 16 | 17 | 18 | ) 19 | return ( 20 | A 21 | , 22 | $response 23 | , 24 | xdmp:log("finished launch.xqy") 25 | ) -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/xquery/library.xqy: -------------------------------------------------------------------------------- 1 | xquery version "1.0-ml"; 2 | module namespace hello = "helloworld"; 3 | 4 | declare function helloworld() 5 | { 6 | "hello world" 7 | }; -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/xquery/longTest.xqy: -------------------------------------------------------------------------------- 1 | xquery version "1.0-ml"; 2 | 3 | import module namespace hw = "helloworld" at "/xquery/library.xqy"; 4 | 5 | declare function local:factorial( 6 | $n as xs:unsignedLong? 7 | ) as xs:unsignedLong { 8 | if (fn:empty($n) or $n le 1) then 9 | 1 10 | else 11 | $n * local:factorial( 12 | $n - 1 13 | ) 14 | }; 15 | 16 | let $_ := xdmp:log("running longTest.xqy") 17 | let $three := 3 18 | let $steps := (1, 2, $three) 19 | let $squares := 20 | for $step in $steps 21 | return $step * $step 22 | let $_ := xdmp:log(("Squares", $squares)) 23 | let $result := local:factorial(5) 24 | let $_ := xdmp:log(("Factorial result", $result)) 25 | return $result -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/xquery/overrideTest.xqy: -------------------------------------------------------------------------------- 1 | (: mlxprs:settings 2 | { 3 | "host": "localhost", 4 | "authType": "BASIC", 5 | "managePort": 8059, 6 | "port": 8057, 7 | "contentDb": "mlxprs-test-content", 8 | "modulesDb": "mlxprs-test-modules", 9 | "user": "admin", 10 | "pwd": "admin", 11 | "note": "These settings are for testing only", 12 | "ssl": true, 13 | "rejectUnauthorized": false 14 | } 15 | :) 16 | (: 17 | , 18 | "pathToCa": "/Users/pbarber/Documents/workspaces/engineering/GdsSelfSignedCert/fromTemplate.crt" 19 | :) 20 | xquery version "1.0-ml"; 21 | 22 | import module namespace hw = "helloworld" at "/xquery/library.xqy"; 23 | 24 | declare function local:factorial( 25 | $n as xs:unsignedLong? 26 | ) as xs:unsignedLong { 27 | if (fn:empty($n) or $n le 1) then 28 | 1 29 | else 30 | $n * local:factorial( 31 | $n - 1 32 | ) 33 | }; 34 | 35 | let $_ := xdmp:log("running longTest.xqy") 36 | let $three := 3 37 | let $steps := (1, 2, $three) 38 | let $squares := 39 | for $step in $steps 40 | return $step * $step 41 | let $_ := xdmp:log(("Squares", $squares)) 42 | let $result := local:factorial(7) 43 | let $_ := xdmp:log(("Factorial result", $result)) 44 | return $result -------------------------------------------------------------------------------- /test-app/src/main/ml-modules/root/xquery/testXqy.xqy: -------------------------------------------------------------------------------- 1 | xquery version "1.0-ml"; 2 | 3 | let $_ := xdmp:log($msg, [$level]) 4 | let $_ := fn:abs($arg) 5 | let $_ := cts:and-query($queries, [$options]) 6 | return () -------------------------------------------------------------------------------- /test-app/src/main/ml-schemas/tde/authors-TDE.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": { 3 | "context": "/Citations/Citation/Article/AuthorList/Author", 4 | "rows": [ 5 | { 6 | "schemaName": "Medical", 7 | "viewName": "Authors", 8 | "columns": [ 9 | { 10 | "name": "ID", 11 | "scalarType": "long", 12 | "val": "../../../ID" 13 | }, 14 | { 15 | "name": "LastName", 16 | "scalarType": "string", 17 | "val": "LastName" 18 | }, 19 | { 20 | "name": "ForeName", 21 | "scalarType": "string", 22 | "val": "ForeName" 23 | }, 24 | { 25 | "name": "Date", 26 | "scalarType": "date", 27 | "val": "../../Journal/JournalIssue/PubDate/Year || '-' || ../../Journal/JournalIssue/PubDate/Month || '-' || ../../Journal/JournalIssue/PubDate/Day" 28 | }, 29 | { 30 | "name": "DateTime", 31 | "scalarType": "dateTime", 32 | "val": "../../Journal/JournalIssue/PubDate/Year || '-' || ../../Journal/JournalIssue/PubDate/Month || '-' || ../../Journal/JournalIssue/PubDate/Day || 'T' || ../../Journal/JournalIssue/PubDate/Time" 33 | } 34 | ] 35 | } 36 | ], 37 | 38 | "vars":[ 39 | { 40 | "name":"YYYY", 41 | "val":"YYYY.xml" 42 | }, 43 | { 44 | "name":"MLXPRS_TEST_URI", 45 | "val":"/citations.xml" 46 | }, 47 | { 48 | "name":"ZZZZ", 49 | "val":"ZZZZ.xml" 50 | } 51 | ] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test-app/src/main/ml-schemas/tde/authors-local-data-TDE.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": { 3 | "context": "/Citations/Citation/Article/AuthorList/Author", 4 | "rows": [ 5 | { 6 | "schemaName": "Medical", 7 | "viewName": "Authors", 8 | "columns": [ 9 | { 10 | "name": "ID", 11 | "scalarType": "long", 12 | "val": "../../../ID" 13 | }, 14 | { 15 | "name": "LastName", 16 | "scalarType": "string", 17 | "val": "LastName" 18 | }, 19 | { 20 | "name": "ForeName", 21 | "scalarType": "string", 22 | "val": "ForeName" 23 | }, 24 | { 25 | "name": "Date", 26 | "scalarType": "date", 27 | "val": "../../Journal/JournalIssue/PubDate/Year || '-' || ../../Journal/JournalIssue/PubDate/Month || '-' || ../../Journal/JournalIssue/PubDate/Day" 28 | }, 29 | { 30 | "name": "DateTime", 31 | "scalarType": "dateTime", 32 | "val": "../../Journal/JournalIssue/PubDate/Year || '-' || ../../Journal/JournalIssue/PubDate/Month || '-' || ../../Journal/JournalIssue/PubDate/Day || 'T' || ../../Journal/JournalIssue/PubDate/Time" 33 | } 34 | ] 35 | } 36 | ], 37 | "vars": [ 38 | { 39 | "name": "MLXPRS_TEST_FILE", 40 | "val": "src/test/resources/localCitationsData.xml" 41 | } 42 | ] 43 | } 44 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-schemas/tde/no-var-authors-TDE.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": { 3 | "context": "/Citations/Citation/Article/AuthorList/Author", 4 | "rows": [ 5 | { 6 | "schemaName": "Medical", 7 | "viewName": "SmallAuthors", 8 | "columns": [ 9 | { 10 | "name": "ID", 11 | "scalarType": "long", 12 | "val": "../../../ID" 13 | }, 14 | { 15 | "name": "LastName", 16 | "scalarType": "string", 17 | "val": "LastName" 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test-app/src/main/ml-schemas/tde/no-var-publications-TDE.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/src/main/ml-schemas/tde/publications-TDE.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/src/main/ml-schemas/tde/publications-local-data-TDE.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/src/main/ml-schemas/tde/small-authors-TDE.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": { 3 | "context": "/Citations/Citation/Article/AuthorList/Author", 4 | "rows": [ 5 | { 6 | "schemaName": "Medical", 7 | "viewName": "SmallAuthors", 8 | "columns": [ 9 | { 10 | "name": "ID", 11 | "scalarType": "long", 12 | "val": "../../../ID" 13 | }, 14 | { 15 | "name": "LastName", 16 | "scalarType": "string", 17 | "val": "LastName" 18 | } 19 | ] 20 | } 21 | ], 22 | 23 | "vars":[ 24 | { 25 | "name":"MLXPRS_TEST_URI", 26 | "val":"citations.xml" 27 | } 28 | ] 29 | } 30 | } -------------------------------------------------------------------------------- /test-app/src/test/ml-modules/root/test/suites/SampleJavaScriptTestSuite/sample-failing-jstest.sjs: -------------------------------------------------------------------------------- 1 | const test = require('/test/test-helper.xqy'); 2 | const f = require('/lib/factorial.sjs'); 3 | 4 | let assertions = []; 5 | 6 | assertions.push( 7 | test.assertEqual(1, f.factorial(1)), 8 | test.assertEqual(0, f.factorial(2)), 9 | test.assertEqual(6, f.factorial(3)) 10 | ); 11 | 12 | assertions; -------------------------------------------------------------------------------- /test-app/src/test/ml-modules/root/test/suites/SampleJavaScriptTestSuite/sample-jstest.sjs: -------------------------------------------------------------------------------- 1 | const test = require('/test/test-helper.xqy'); 2 | const f = require('/lib/factorial.sjs'); 3 | 4 | let assertions = []; 5 | 6 | assertions.push( 7 | test.assertEqual(1, f.factorial(1)), 8 | test.assertEqual(2, f.factorial(2)), 9 | test.assertEqual(6, f.factorial(3)), 10 | test.assertEqual(24, f.factorial(4)), 11 | test.assertEqual(120, f.factorial(5)) 12 | ); 13 | 14 | assertions; -------------------------------------------------------------------------------- /test-app/src/test/ml-modules/root/test/suites/SampleJavaScriptTestSuite/setup.sjs: -------------------------------------------------------------------------------- 1 | console.debug('sample-tests Setup COMPLETE....'); -------------------------------------------------------------------------------- /test-app/src/test/ml-modules/root/test/suites/SampleXQueryTestSuite/sample-tests.xqy: -------------------------------------------------------------------------------- 1 | xquery version '1.0-ml'; 2 | 3 | import module namespace test = 'http://marklogic.com/test' at '/test/test-helper.xqy'; 4 | 5 | test:success(), 6 | test:log("sample-tests COMPLETE....") -------------------------------------------------------------------------------- /test-app/src/test/ml-modules/root/test/suites/SampleXQueryTestSuite/setup.xqy: -------------------------------------------------------------------------------- 1 | xquery version '1.0-ml'; 2 | 3 | import module namespace test = 'http://marklogic.com/test' at '/test/test-helper.xqy'; 4 | 5 | (: 6 | This module will be run before each test in your suite. 7 | Here you might insert a document into the test database that each of your tests will modify. 8 | If no test-specific setup is required, this file may be deleted. 9 | Each setup runs in its own transaction. 10 | :) 11 | test:log("sample-tests Setup COMPLETE....") -------------------------------------------------------------------------------- /test-app/src/test/ml-modules/root/test/suites/SampleXQueryTestSuite/suite-setup.xqy: -------------------------------------------------------------------------------- 1 | xquery version '1.0-ml'; 2 | 3 | import module namespace test = 'http://marklogic.com/test' at '/test/test-helper.xqy'; 4 | 5 | (: 6 | Runs once when your suite is started. 7 | You can use this to insert some data that will not be modified over the course of the suite's tests. 8 | If no suite-specific setup is required, this file may be deleted. 9 | :) 10 | test:log("SampleTestSuite Suite Setup COMPLETE....") -------------------------------------------------------------------------------- /test-app/src/test/ml-modules/root/test/suites/SampleXQueryTestSuite/suite-teardown.xqy: -------------------------------------------------------------------------------- 1 | xquery version '1.0-ml'; 2 | 3 | import module namespace test = 'http://marklogic.com/test' at '/test/test-helper.xqy'; 4 | 5 | (: 6 | Runs once when your suite is finished, to clean up after the suite's tests. 7 | If no suite-specific teardown is required, this file may be deleted. 8 | :) 9 | test:log("SampleTestSuite Suite Teardown ENDING....") -------------------------------------------------------------------------------- /test-app/src/test/ml-modules/root/test/suites/SampleXQueryTestSuite/teardown.xqy: -------------------------------------------------------------------------------- 1 | xquery version '1.0-ml'; 2 | 3 | import module namespace test = 'http://marklogic.com/test' at '/test/test-helper.xqy'; 4 | 5 | (: 6 | This module will run after each test in your suite. 7 | You might use this module to remove the document inserted by the test setup module. 8 | If no test-specific teardown is required, this file may be deleted. 9 | :) 10 | test:log("sample-tests Teardown COMPLETE....") -------------------------------------------------------------------------------- /test-app/src/test/resources/localCitationsData.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 |
5 | 6 | 11111-111 7 | 8 | 44 9 | 10 | 2002-07-13 11 | 2002 12 | 07 13 | 13 14 | 15 | 16 | 17 | 18 | 19 | 20 | Washington 21 | George 22 | 23 | 24 | Lincoln 25 | Abraham 26 | 27 | 28 |
29 |
30 | 31 | 2 32 |
33 | 34 | 22222-2222 35 | 36 | 0 37 | 38 | 2002-05-11 39 | 2002 40 | 05 41 | 11 42 | 43 | 44 | 45 | 46 | 47 | 48 | Jefferson 49 | Thomas 50 | 51 | 52 |
53 |
54 |
55 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "dist", 6 | "lib": [ "es6" ], 7 | "sourceMap": true, 8 | "rootDir": "client", 9 | 10 | // "noUnusedLocals": true, 11 | // "noUnusedParameters": true, 12 | // "noImplicitAny": true, 13 | "noImplicitReturns": true 14 | }, 15 | "exclude": [ 16 | "node_modules", 17 | ".vscode-test", 18 | "server" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable @typescript-eslint/no-var-requires */ 18 | //@ts-check 19 | 20 | 'use strict' 21 | 22 | const withDefaults = require('./shared.webpack.config') 23 | const path = require('path') 24 | 25 | module.exports = withDefaults({ 26 | context: path.join(__dirname), 27 | entry: { 28 | extension: './client/extension.ts', 29 | xqyDebug: './client/XQDebugger/xqyDebug.ts', 30 | jsDebug: './client/JSDebugger/mlDebug.ts' 31 | } 32 | }) 33 | -------------------------------------------------------------------------------- /webpack.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 MarkLogic Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable @typescript-eslint/no-var-requires */ 18 | //@ts-check 19 | 20 | 'use strict' 21 | 22 | const withDefaults = require('./shared.webpack.config') 23 | const path = require('path') 24 | 25 | module.exports = withDefaults({ 26 | context: path.join(__dirname), 27 | entry: { 28 | mlDebug: './client/JSDebugger/mlDebug.ts' 29 | } 30 | }) 31 | -------------------------------------------------------------------------------- /xquery-ml.configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "blockComment": [ "(:", ":)" ] 4 | }, 5 | "brackets": [ 6 | ["{", "}"], 7 | ["[", "]"], 8 | ["(", ")"] 9 | ], 10 | "autoClosingPairs": [ 11 | ["{", "}"], 12 | ["[", "]"], 13 | ["(", ")"], 14 | ["\"", "\""], 15 | ["'", "'"], 16 | ["(:", ":)"] 17 | ], 18 | "surroundingPairs": [ 19 | ["{", "}"], 20 | ["[", "]"], 21 | ["(", ")"], 22 | ["\"", "\""], 23 | ["'", "'"], 24 | ["(:", ":)"] 25 | ] 26 | } 27 | --------------------------------------------------------------------------------