From 4814107ce1840d92c2ab0de99e31887014453d4c Mon Sep 17 00:00:00 2001 From: Sergio Oliveira Date: Thu, 24 Nov 2022 20:12:14 +0100 Subject: [PATCH] Split psl-parser from original repo --- .github/ISSUE_TEMPLATE/bug_report.md | 7 +- .github/workflows/build_test_vscode.yml | 3 - .github/workflows/publish_vscode.yml | 48 - .gitignore | 2 - src/parser/.npmignore => .npmignore | 0 .travis.yml | 61 -- .vscode/launch.json | 84 -- .vscodeignore | 16 - README.md | 161 +--- __tests__/config-test.ts | 32 - __tests__/convention-test.ts | 57 -- __tests__/duplicateProperty-test.ts | 96 -- __tests__/files/ZDuplicateProperty.PROC | 14 - __tests__/files/ZMethodDoc.PROC | 34 - __tests__/files/ZMultiLineDeclare.PROC | 16 - __tests__/files/ZRuntime.PROC | 54 -- __tests__/files/ZTblColDocTst-Col1.COL | 43 - __tests__/files/ZTblColDocTst-Col2.COL | 42 - __tests__/files/ZTblColDocTst-Col3.COL | 37 - __tests__/files/ZTblColDocTst-Col4.COL | 41 - __tests__/files/ZTblColDocTst-Col5.COL | 42 - __tests__/files/ZTblColDocTst-Col6.COL | 37 - __tests__/files/ZTblColDocTst1.TBL | 43 - __tests__/files/ZTblColDocTst2.TBL | 43 - __tests__/files/ZTblColDocTst3.TBL | 42 - __tests__/files/ZTblColDocTst4.TBL | 46 - __tests__/files/ZTblColDocTst5.TBL | 43 - __tests__/files/ZTblColDocTst6.TBL | 41 - __tests__/files/ZTestConvention.PROC | 26 - __tests__/files/ZTestParams.PROC | 40 - __tests__/methodDoc-test.ts | 65 -- __tests__/multiLineDeclare-test.ts | 136 --- __tests__/parameters-test.ts | 44 - __tests__/ruleUtils.ts | 32 - __tests__/runtime-test.ts | 67 -- __tests__/tblcolDoc-test.ts | 76 -- icons/dark/arrow-down.svg | 73 -- icons/dark/arrow-up.svg | 73 -- icons/dark/gear.svg | 73 -- icons/dark/link.svg | 73 -- icons/dark/sync.svg | 73 -- icons/dark/triangle-right.svg | 69 -- icons/light/arrow-down.svg | 12 - icons/light/arrow-up.svg | 12 - icons/light/gear.svg | 12 - icons/light/link.svg | 12 - icons/light/sync.svg | 12 - icons/light/triangle-right.svg | 68 -- jest.config.js | 12 + languages/def-language-configuration.json | 18 - languages/psl-language-configuration.json | 25 - package-lock.json | 186 +--- package.json | 879 +----------------- schemas/environmentSchema.json | 17 - schemas/environmentsSchema.json | 65 -- snippets/columnDefinition.json | 25 - snippets/psl.json | 89 -- snippets/tableDefinition.json | 26 - src/common/context.ts | 38 - src/common/diagnostics.ts | 55 -- src/common/environment.ts | 347 ------- src/common/statusUtils.ts | 13 - src/common/terminal.ts | 111 --- src/extension.ts | 31 - src/hostCommands/activate.ts | 78 -- src/hostCommands/compileAndLink.ts | 64 -- src/hostCommands/get.ts | 306 ------ src/hostCommands/hostCommandUtils.ts | 154 --- src/hostCommands/pslUnitTest.ts | 228 ----- src/hostCommands/refresh.ts | 122 --- src/hostCommands/run.ts | 67 -- src/hostCommands/runCustom.ts | 150 --- src/hostCommands/send.ts | 117 --- src/hostCommands/testCompile.ts | 209 ----- src/language/activate.ts | 117 --- src/language/codeAction.ts | 100 -- src/language/codeQuality.ts | 153 --- src/language/dataItem.ts | 76 -- src/language/lang.ts | 116 --- src/language/mumps.ts | 54 -- src/language/previewDocumentation.ts | 71 -- src/language/pslDefinitionProvider.ts | 37 - src/language/pslDocument.ts | 61 -- src/language/pslFormat.ts | 79 -- src/language/pslHoverProvider.ts | 40 - src/language/pslSignature.ts | 67 -- src/language/pslSuggest.ts | 62 -- src/mtm/hostSocket.ts | 58 -- src/mtm/mtm.ts | 358 ------- src/mtm/utils.ts | 346 ------- src/parser/.npmrc.psl-parser | 4 - src/parser/README.md | 15 - src/parser/package.json | 22 - src/parser/tsconfig.json | 20 - src/pslLint/activate.ts | 156 ---- src/pslLint/api.ts | 230 ----- src/pslLint/cli/.npmignore | 6 - src/pslLint/cli/.npmrc.psl-lint | 4 - src/pslLint/cli/README.md | 36 - src/pslLint/cli/cli.ts | 212 ----- src/pslLint/cli/package-lock.json | 162 ---- src/pslLint/cli/package.json | 24 - src/pslLint/cli/tsconfig.json | 20 - src/pslLint/config.ts | 83 -- src/pslLint/elementsConventionChecker.ts | 259 ------ src/pslLint/methodDoc.ts | 107 --- src/pslLint/multiLineDeclare.ts | 86 -- src/pslLint/parameters.ts | 36 - src/pslLint/runtime.ts | 177 ---- src/pslLint/tblcolDoc.ts | 43 - src/pslLint/todos.ts | 65 -- syntaxes/JSON.tmLanguage | 386 -------- syntaxes/psl.tmLanguage.json | 530 ----------- {__tests__ => test}/files/ZChild.PROC | 0 {__tests__ => test}/files/ZParent.PROC | 0 .../parser-test.ts => test/parser.test.ts | 0 .../statementParser.test.ts | 0 .../tokenize-test.ts => test/tokenize.test.ts | 0 .../utilities.test.ts | 2 +- tsconfig.json | 21 +- 120 files changed, 76 insertions(+), 10090 deletions(-) delete mode 100644 .github/workflows/publish_vscode.yml rename src/parser/.npmignore => .npmignore (100%) delete mode 100644 .travis.yml delete mode 100644 .vscode/launch.json delete mode 100644 .vscodeignore delete mode 100644 __tests__/config-test.ts delete mode 100644 __tests__/convention-test.ts delete mode 100644 __tests__/duplicateProperty-test.ts delete mode 100644 __tests__/files/ZDuplicateProperty.PROC delete mode 100644 __tests__/files/ZMethodDoc.PROC delete mode 100644 __tests__/files/ZMultiLineDeclare.PROC delete mode 100644 __tests__/files/ZRuntime.PROC delete mode 100644 __tests__/files/ZTblColDocTst-Col1.COL delete mode 100644 __tests__/files/ZTblColDocTst-Col2.COL delete mode 100644 __tests__/files/ZTblColDocTst-Col3.COL delete mode 100644 __tests__/files/ZTblColDocTst-Col4.COL delete mode 100644 __tests__/files/ZTblColDocTst-Col5.COL delete mode 100644 __tests__/files/ZTblColDocTst-Col6.COL delete mode 100644 __tests__/files/ZTblColDocTst1.TBL delete mode 100644 __tests__/files/ZTblColDocTst2.TBL delete mode 100644 __tests__/files/ZTblColDocTst3.TBL delete mode 100644 __tests__/files/ZTblColDocTst4.TBL delete mode 100644 __tests__/files/ZTblColDocTst5.TBL delete mode 100644 __tests__/files/ZTblColDocTst6.TBL delete mode 100644 __tests__/files/ZTestConvention.PROC delete mode 100644 __tests__/files/ZTestParams.PROC delete mode 100644 __tests__/methodDoc-test.ts delete mode 100644 __tests__/multiLineDeclare-test.ts delete mode 100644 __tests__/parameters-test.ts delete mode 100644 __tests__/ruleUtils.ts delete mode 100644 __tests__/runtime-test.ts delete mode 100644 __tests__/tblcolDoc-test.ts delete mode 100644 icons/dark/arrow-down.svg delete mode 100644 icons/dark/arrow-up.svg delete mode 100644 icons/dark/gear.svg delete mode 100644 icons/dark/link.svg delete mode 100644 icons/dark/sync.svg delete mode 100644 icons/dark/triangle-right.svg delete mode 100644 icons/light/arrow-down.svg delete mode 100644 icons/light/arrow-up.svg delete mode 100644 icons/light/gear.svg delete mode 100644 icons/light/link.svg delete mode 100644 icons/light/sync.svg delete mode 100644 icons/light/triangle-right.svg create mode 100644 jest.config.js delete mode 100644 languages/def-language-configuration.json delete mode 100644 languages/psl-language-configuration.json delete mode 100644 schemas/environmentSchema.json delete mode 100644 schemas/environmentsSchema.json delete mode 100644 snippets/columnDefinition.json delete mode 100644 snippets/psl.json delete mode 100644 snippets/tableDefinition.json delete mode 100644 src/common/context.ts delete mode 100644 src/common/diagnostics.ts delete mode 100644 src/common/environment.ts delete mode 100644 src/common/statusUtils.ts delete mode 100644 src/common/terminal.ts delete mode 100644 src/extension.ts delete mode 100644 src/hostCommands/activate.ts delete mode 100644 src/hostCommands/compileAndLink.ts delete mode 100644 src/hostCommands/get.ts delete mode 100644 src/hostCommands/hostCommandUtils.ts delete mode 100644 src/hostCommands/pslUnitTest.ts delete mode 100644 src/hostCommands/refresh.ts delete mode 100644 src/hostCommands/run.ts delete mode 100644 src/hostCommands/runCustom.ts delete mode 100644 src/hostCommands/send.ts delete mode 100644 src/hostCommands/testCompile.ts delete mode 100644 src/language/activate.ts delete mode 100644 src/language/codeAction.ts delete mode 100644 src/language/codeQuality.ts delete mode 100644 src/language/dataItem.ts delete mode 100644 src/language/lang.ts delete mode 100644 src/language/mumps.ts delete mode 100644 src/language/previewDocumentation.ts delete mode 100644 src/language/pslDefinitionProvider.ts delete mode 100644 src/language/pslDocument.ts delete mode 100644 src/language/pslFormat.ts delete mode 100644 src/language/pslHoverProvider.ts delete mode 100644 src/language/pslSignature.ts delete mode 100644 src/language/pslSuggest.ts delete mode 100644 src/mtm/hostSocket.ts delete mode 100644 src/mtm/mtm.ts delete mode 100644 src/mtm/utils.ts delete mode 100644 src/parser/.npmrc.psl-parser delete mode 100644 src/parser/README.md delete mode 100644 src/parser/package.json delete mode 100644 src/parser/tsconfig.json delete mode 100644 src/pslLint/activate.ts delete mode 100644 src/pslLint/api.ts delete mode 100644 src/pslLint/cli/.npmignore delete mode 100644 src/pslLint/cli/.npmrc.psl-lint delete mode 100644 src/pslLint/cli/README.md delete mode 100644 src/pslLint/cli/cli.ts delete mode 100644 src/pslLint/cli/package-lock.json delete mode 100644 src/pslLint/cli/package.json delete mode 100644 src/pslLint/cli/tsconfig.json delete mode 100644 src/pslLint/config.ts delete mode 100644 src/pslLint/elementsConventionChecker.ts delete mode 100644 src/pslLint/methodDoc.ts delete mode 100644 src/pslLint/multiLineDeclare.ts delete mode 100644 src/pslLint/parameters.ts delete mode 100644 src/pslLint/runtime.ts delete mode 100644 src/pslLint/tblcolDoc.ts delete mode 100644 src/pslLint/todos.ts delete mode 100644 syntaxes/JSON.tmLanguage delete mode 100644 syntaxes/psl.tmLanguage.json rename {__tests__ => test}/files/ZChild.PROC (100%) rename {__tests__ => test}/files/ZParent.PROC (100%) rename __tests__/parser-test.ts => test/parser.test.ts (100%) rename __tests__/statementParser-test.ts => test/statementParser.test.ts (100%) rename __tests__/tokenize-test.ts => test/tokenize.test.ts (100%) rename __tests__/utilities-test.ts => test/utilities.test.ts (99%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 624bca8..b5795bc 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -25,8 +25,11 @@ If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. iOS] - - vscode version: [e.g. 1.72.2] - - vscode-psl version[e.g. 1.12.1] + - psl-parser version: [e.g. 1.72.2] + - node version[e.g. 1.12.1] + +**Error output** +Add the error information available. **Additional context** Add any other context about the problem here. diff --git a/.github/workflows/build_test_vscode.yml b/.github/workflows/build_test_vscode.yml index 863d53a..d5bc344 100644 --- a/.github/workflows/build_test_vscode.yml +++ b/.github/workflows/build_test_vscode.yml @@ -21,8 +21,5 @@ jobs: node-version: '16.x' cache: 'npm' - run: npm install - - run: cd src/pslLint/cli && npm install && cd - - name: Install psl-lint CLI dependencies - run: npm run compile - - run: npm run compile-lint - run: npm test diff --git a/.github/workflows/publish_vscode.yml b/.github/workflows/publish_vscode.yml deleted file mode 100644 index 8e20e47..0000000 --- a/.github/workflows/publish_vscode.yml +++ /dev/null @@ -1,48 +0,0 @@ -# This workflow will build and publish the plugin on tag create - -name: Publish vscode-psl - -on: - push: - tags: 'vscode*' - -jobs: - test: - name: Build and test - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Use Node.js - uses: actions/setup-node@v3 - with: - node-version: '16.x' - cache: 'npm' - - run: npm install - - run: cd src/pslLint/cli && npm install && cd - - name: Install psl-lint CLI dependencies - - run: npm run compile - - run: npm run compile-lint - - run: npm test - - publish: - needs: test - name: Publish vscode-psl - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Use Node.js - uses: actions/setup-node@v3 - with: - node-version: '16.x' - cache: 'npm' - - run: npm install . - - env: - VSCODE_TOKEN: ${{ secrets.VSCODE_TOKEN_PUBLISH }} - if: ${{ contains(github.ref, '-rc') }} - run: npm run compile && npm i -g vsce && vsce package --pre-release && vsce publish --pre-release -p $VSCODE_TOKEN - name: Publish Pre-Release - - env: - VSCODE_TOKEN: ${{ secrets.VSCODE_TOKEN_PUBLISH }} - run: npm run compile && npm i -g vsce && vsce package && vsce publish -p $VSCODE_TOKEN - if: ${{ ! contains(github.ref, '-rc') }} - name: Publish Release diff --git a/.gitignore b/.gitignore index 848d265..6db501b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,4 @@ node_modules *.vsix .project .settings -src/hostif/target/* .classpath -src/pslLint/cli/lib/* \ No newline at end of file diff --git a/src/parser/.npmignore b/.npmignore similarity index 100% rename from src/parser/.npmignore rename to .npmignore diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 35e2e8e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,61 +0,0 @@ -sudo: false -dist: trusty -language: node_js -node_js: - - "10" - -stages: - - build - - name: deploy parser - if: tag =~ ^parser - - name: deploy lint - if: tag =~ ^lint - - name: deploy vscode - if: tag =~ ^vscode - -jobs: - include: - - stage: build - script: - - npm run compile - - npm run compile-lint - name: compile - - script: - - npm run lint - name: lint - - script: - - npm run test - name: test - - - stage: deploy parser - script: cp ./src/parser/.npmrc.psl-parser .npmrc && npm run compile-parser - deploy: - provider: script - script: npm publish ./src/parser - skip_cleanup: true - on: - tags: true - all_branches: true - name: npm - - - stage: deploy lint - script: cp ./src/pslLint/cli/.npmrc.psl-lint .npmrc && npm run compile-lint - deploy: - provider: script - script: npm publish ./src/pslLint/cli - skip_cleanup: true - on: - tags: true - all_branches: true - name: npm - - - stage: deploy vscode - script: npm run compile && npm i -g vsce && vsce package - deploy: - provider: script - script: vsce publish -p $VSCODE_TOKEN - skip_cleanup: true - on: - tags: true - all_branches: true - name: marketplace diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 08b85f7..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,84 +0,0 @@ -// A launch configuration that compiles the extension and then opens it inside a new window -{ - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "attach", - "name": "Attach by Process ID", - "processId": "${command:PickProcess}" - }, - { - "name": "Attach to docker", - "type": "node", - "request": "attach", - "port": 5858, - "address": "localhost", - "sourceMaps": true, - "outFiles": [], - "localRoot": "${workspaceRoot}/src/pslLint/cli", - "remoteRoot": "/app" - }, - { - "name": "Launch Extension", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceRoot}" - ], - "stopOnEntry": false, - "sourceMaps": true, - "outFiles": [ - "${workspaceRoot}/out/src/**/*.js" - ], - "preLaunchTask": "watch" - }, - { - "name": "Debug CLI", - "type": "node", - "request": "launch", - "program": "${workspaceRoot}/src/pslLint/cli/lib/pslLint/cli/cli.js", - "args": [ - "." - ], - "stopOnEntry": false, - "sourceMaps": true, - "outFiles": [ - "${workspaceRoot}/src/pslLint/cli/lib/**/*.js" - ], - "preLaunchTask": "watch" - }, - { - "type": "node", - "request": "launch", - "name": "Debug Tests", - "program": "${workspaceRoot}/node_modules/jest/bin/jest.js", - "args": [ - "--runInBand" - ], - "internalConsoleOptions": "openOnSessionStart", - "outFiles": [ - "${workspaceRoot}/out/**/*" - ], - "preLaunchTask": "watch" - }, - { - "name": "Launch Tests", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "${workspaceRoot}/test/dataqwik/procedure/test.PROC", - "--extensionDevelopmentPath=${workspaceRoot}", - "--extensionTestsPath=${workspaceRoot}/out/test" - ], - "stopOnEntry": false, - "sourceMaps": true, - "outFiles": [ - "${workspaceRoot}/out/test/**/*.js" - ], - "preLaunchTask": "watch" - } - ] -} diff --git a/.vscodeignore b/.vscodeignore deleted file mode 100644 index 5c3d81b..0000000 --- a/.vscodeignore +++ /dev/null @@ -1,16 +0,0 @@ -.vscode/** -.vscode-test/** -out/test/** -test/** -src/** -**/*.map -.gitignore -tsconfig.json -vsc-extension-quickstart.md -*.html -*.vsix -*.pyc -!src/python/** -python_scripts/** -images/** -package-lock.json diff --git a/README.md b/README.md index c0736f7..5a90d53 100644 --- a/README.md +++ b/README.md @@ -1,166 +1,23 @@ -# vscode-psl - +# psl-parser [![Build and Test CI](https://github.com/ing-bank/vscode-psl/actions/workflows/build_test_vscode.yml/badge.svg)](https://github.com/ing-bank/vscode-psl/actions/workflows/build_test_vscode.yml) -Profile Scripting Language functionality for Visual Studio Code. - -## Dependencies - -* Visual Studio Code version 1.72.2 or higher. - -## Environment Configuration - -Locate the button at the bottom-right corner titled `Configure Environments`. If the button is not visible, use the Command Palette (F1 or Ctrl+Shift+P) to find the `PSL: Configure Environment` command. A JSON object of the following form will appear: - -```json -{ - "environments": [ - { - "name": "", - "host": "", - "port": 0, - "user": "", - "password": "", - "sshLogin": "", - "serverType": "SCA$IBS", - "encoding": "utf8" - } - ] -} -``` - -> Added in v1.8.0 are the fields `serverType` and `encoding`. Their default values are "SCA$IBS" and "utf8", respectively. - -Here you can store a global array of configurations. Any project can read from this configuration. Use auto-complete and hover suggestions for hints about using the configuration file. - -Once the global configuration is saved, environments can be activated by using the `Configure Environments` button at the bottom. Multiple environments can be selected, allowing for simultaneous interactions with hosts. - -## Host Communication - -Commands to communicate with the Host via MRPC121 can be executed via the Command Pallette (F1 or Ctrl+Shift+P), icons at the top-right corner of the document, right-clicking the document, or right-clicking the file in the Explorer sidebar. - -* `Compile and Link`: Compiles and links PSL or tables -* `Get Element from Host`: Gets a new element -* `Refresh from Host`: Refreshes an existing element -* `Run PSL`: Runs a PSL element "as is" and displays the output -* `Send to Host`: Sends an existing element -* `Table Get from Host`: Gets all elements related to a table -* `Table Refresh from Host`: Fetches all elements related to an existing table element -* `Table Send to Host`: Sends all existing elements related to the table -* `Test Compile`: Test compiles PSL - -> Please note that the Host Communication is done *asynchronously*, meaning that vscode will not require you to wait to finish one action before you start another. This may have unintended consequences if you do not wait. For example, you must wait for sending to finish before you compile and link. - -### Getting New Elements - -Two commands `Get Element from Host` and `Table Get from Host` will allow you to get new elements from the Host. When activating the commands from the editor, the element(s) will try to be placed according to this table: - -|Type | Directory | -|---|---| -BATCH | `dataqwik/batch/` | -DAT | `data/` | -FKY | `dataqwik/foreign_key/` | -IDX | `dataqwik/index/` | -JFD | `dataqwik/journal/` | -m | `routine/` | -PROC | `dataqwik/procedure/` | -properties | `property/` | -QRY | `dataqwik/query/` | -RPT | `dataqwik/report/` | -SCR | `dataqwik/screen/` | -table files (TBL and COL) | `dataqwik/table/{table_name}/` | -TRIG | `dataqwik/trigger/` | - -If an element is not in the table, a prompt will ask where it should be saved. - -In the case of `Table Get from Host`, the TBL and COL files will all be retrieved and placed in the `dataqwik/table/{table_name}/` directory. To get an individual TBL or COL file, use the regular `Get Element from Host` command. - -These two commands behave differently when they are used in the Explorer sidebar, specifically on a directory. In this case, both "Get" commands will place the new element(s) inside the targeted directory. - -### Acting on Tables - -When editing a TBL or COL, the commands `Table Refresh from Host` and `Table Send to Host` are present. - -The "Send" command will act on all existing elements of that table in the project at once, while the "Refresh" command will fetch all elements related to the table from the Host, even elements not present in the project. +TypeScript implementation of a Profile Scripting Language Parser. -`Compile and Link` is also available, allowing you to "Rebuild Data Item Control Files". +## Usage -### Acting on Directories +```javascript +import { parseText } from 'psl-parser'; -The five commands `Compile and Link`, `Refresh from Host`, `Run PSL`, `Send to Host`, and `Test Compile` can all be executed on directories from the Explorer sidebar. In this case a dialogue box will open, allowing you to act on multiple elements within the directory at once. - -## Language Features - -Basic language features also exist for files written in PSL, data configuration, and table files. - -These features include: - -* Syntax coloring -* Property and Label outline for PSL files (access by Ctrl+Shift+O or by enabling the built-in outline). -* Code Completion, Hovers, and Go-To Definitions. -* Highlighting and Hover information for editing data configuration files -* Code snippets for loops, comments, and table/column definitions, etc. - -## psl-lint - -This extension includes support for checking PSL against common coding standards. The setting `psl.lint` is by default set to `config`, meaning the linting module will activate upon finding a `psl-lint.json` configuration file. Here is a sample: +const parsedPsl = parseText(/* PSL source text */); +parsedPsl.methods.forEach(method => { + console.log(method.id.value); +}) ``` -{ - "version": 1, - "include": { - "Z*": ["*"], - "*": ["TodoInfo"] - }, - "exclude": { - "ZRPC*.PROC": ["MemberCamelCase"] - } -} -``` - -Within `include` and `exclude` are mappings from filename patterns to Rules. These are glob-style patterns ("Z*" will match all files that start with Z). The Rules are written in an array, and must be explicitly stated. The only exception is "*", which matches all Rules. - -[For more information about which Rules are available, and how the linting can be used as a tool outside of vscode, visit the package at npm](https://www.npmjs.com/package/psl-lint). - -## Debugging GT.M - -The extension can be configured to help you debug in the Integrated Terminal with the following actions: - -* Step In (Ctrl+Q): `ZSTEP INTO:"W $ZPOS ZP @$ZPOS B"` -* Step Over (Ctrl+W): `ZSTEP OVER:"W $ZPOS ZP @$ZPOS B"` -* Step Out (Ctrl+E): `ZSTEP OUTOF:"W $ZPOS ZP @$ZPOS B"` - -By toggling the status bar item "GT.M Debug", the extension can send the text to your active Integrated Terminal. The default values are presented above, but can be customized to your liking. - -The setting `psl.gtmDebugEnabled` can be set to `true` to keep "GT.M Debug" on by default. - -You may even define custom sequences using the `psl.sendToHostTerminal` command. `key` and `args` are completely configurable. You can add as many of these configurations as you would like to your `keybindings.json`: - -``` -{ - "key": "ctrl+1", - "args": "d ^DRV\n1\nxxx", - "command": "psl.sendToHostTerminal", - "when": "terminalFocus && psl.gtmDebug" -} -``` - -The `psl.gtmDebug` context value guarantees the shortcuts are only enabled when "GT.M Debug" is toggled on. This can be omitted for "always on" shortcuts. - -## Available Settings - -* `psl.lint`: Whether to lint files written in PSL. The default value is `config`, which means linting only activates when the `psl-lint.json` config file is present. [Read more here](#psl-lint). -* `psl.previewFeatures`: Set true to enable the latest developing features. Default value is false. -* `psl.gtmDebug`: Set true to keep GT.M Debug on by default. -* `psl.trailingNewline`: Adds a trailing newline after a "Get" or "Refresh". The default behavior is to not change the output. ## Development If you would like to join the development of this extension, you will need to install [node.js](https://nodejs.org/en/) (with npm) in order to install the dependencies. Once you clone the project, from the command line in the root of this project, run `npm install`. - -For ideas on features to implement, visit the below link: - -https://code.visualstudio.com/docs/extensions/language-support diff --git a/__tests__/config-test.ts b/__tests__/config-test.ts deleted file mode 100644 index c7f5631..0000000 --- a/__tests__/config-test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Config, matchConfig, transform } from '../src/pslLint/config'; - -const config: Config = { - exclude: { - 'ZRPC.PROC': ['*'], - }, - include: { - '*': ['TodoInfo'], - '*.psl': ['*'], - 'Z*': ['*'], - }, -}; - -test('does not match ZRPC.PROC', () => { - expect(matchConfig('ZRPC.PROC', 'arule', transform(config))).toEqual(false); -}); - -test('does match x.psl', () => { - expect(matchConfig('x.psl', 'arule', transform(config))).toEqual(true); -}); - -test('does match ZRPC1.PROC', () => { - expect(matchConfig('ZRPC1.PROC', 'arule', transform(config))).toEqual(true); -}); - -test('TodoInfo match A.PROC', () => { - expect(matchConfig('A.PROC', 'TodoInfo', transform(config))).toEqual(true); -}); - -test('arule match A.PROC', () => { - expect(matchConfig('A.PROC', 'arule', transform(config))).toEqual(false); -}); diff --git a/__tests__/convention-test.ts b/__tests__/convention-test.ts deleted file mode 100644 index 38f21a5..0000000 --- a/__tests__/convention-test.ts +++ /dev/null @@ -1,57 +0,0 @@ -import * as api from '../src/pslLint/api'; -import { - MemberCamelCase, MemberLength, - MemberLiteralCase, MemberStartsWithV, PropertyIsDummy } from '../src/pslLint/elementsConventionChecker'; -import * as utils from './ruleUtils'; - -describe('Members tests', () => { - let literalDiagnostics: api.Diagnostic[] = []; - let camelCaseDiagnostics: api.Diagnostic[] = []; - let lengthDiagnostics: api.Diagnostic[] = []; - let vDiagnostics: api.Diagnostic[] = []; - let withoutDummyDiagnostics: api.Diagnostic[] = []; - let withDummyDiagnostics: api.Diagnostic[] = []; - - beforeAll(async () => { - literalDiagnostics = await utils.getDiagnostics('ZTestConvention.PROC', MemberLiteralCase.name); - camelCaseDiagnostics = await utils.getDiagnostics('ZTestConvention.PROC', MemberCamelCase.name); - lengthDiagnostics = await utils.getDiagnostics('ZTestConvention.PROC', MemberLength.name); - vDiagnostics = await utils.getDiagnostics('ZTestConvention.PROC', MemberStartsWithV.name); - withoutDummyDiagnostics = await utils.getDiagnostics('ZTestConvention.PROC', PropertyIsDummy.name); - withDummyDiagnostics = await utils.getDiagnostics('ZParent.PROC', PropertyIsDummy.name); - }); - - test('Upper case literal report', () => { - expect(utils.diagnosticsOnLine(5, literalDiagnostics).length).toBe(1); - }); - - test('Camel case literal report', () => { - expect(utils.diagnosticsOnLine(4, camelCaseDiagnostics).length).toBe(1); - }); - - test('More than 25 characters', () => { - expect(utils.diagnosticsOnLine(14, lengthDiagnostics).length).toBe(1); - }); - - test('Starts with v', () => { - const diagnosticsOnLine = utils.diagnosticsOnLine(23, vDiagnostics); - expect(diagnosticsOnLine.length).toBe(1); - expect(diagnosticsOnLine[0].message).toBe(`Declaration "vString" starts with 'v'.`); - expect(diagnosticsOnLine[0].severity).toBe(api.DiagnosticSeverity.Warning); - }); - test('Public starts with v', () => { - const diagnosticsOnLine = utils.diagnosticsOnLine(24, vDiagnostics); - expect(diagnosticsOnLine.length).toBe(1); - expect(diagnosticsOnLine[0].message).toBe(`Declaration "vNumber" is public and starts with 'v'.`); - expect(diagnosticsOnLine[0].severity).toBe(api.DiagnosticSeverity.Information); - }); - - test('Property was not called \'dummy\'', () => { - expect(withoutDummyDiagnostics.length).toBe(0); - }); - - test('Property was called \'dummy\'', () => { - expect(utils.diagnosticsOnLine(2, withDummyDiagnostics).length).toBe(1); - }); - -}); diff --git a/__tests__/duplicateProperty-test.ts b/__tests__/duplicateProperty-test.ts deleted file mode 100644 index e5a4c80..0000000 --- a/__tests__/duplicateProperty-test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import * as api from '../src/pslLint/api'; -import { PropertyIsDuplicate } from '../src/pslLint/elementsConventionChecker'; -import * as utils from './ruleUtils'; - -describe('Parameter tests', () => { - - let propertyisDuplicate: api.Diagnostic[] = []; - - beforeAll(async () => { - propertyisDuplicate = await utils.getDiagnostics('ZDuplicateProperty.PROC', PropertyIsDuplicate.name); - }); - - test('line 1', () => { - const diagnostics = utils.diagnosticsOnLine(1, propertyisDuplicate); - expect(diagnostics.length).toBe(0); - }); - - test('line 2', () => { - const diagnostics = utils.diagnosticsOnLine(2, propertyisDuplicate); - expect(diagnostics.length).toBe(0); - }); - - test('line 3', () => { - const test1Message = 'Property "aCCount" is already declared with different case.'; - const diagnostics = utils.diagnosticsOnLine(3, propertyisDuplicate); - expect(diagnostics.length).toBe(1); - expect(diagnostics[0].message).toBe(test1Message); - }); - - test('line 4', () => { - const test1Message = 'Property "accounT" is already declared with different case.'; - const diagnostics = utils.diagnosticsOnLine(4, propertyisDuplicate); - expect(diagnostics.length).toBe(1); - expect(diagnostics[0].message).toBe(test1Message); - }); - - test('line 5', () => { - const diagnostics = utils.diagnosticsOnLine(5, propertyisDuplicate); - expect(diagnostics.length).toBe(0); - }); - - test('line 6', () => { - const test1Message = 'Property "customer" is already declared.'; - const diagnostics = utils.diagnosticsOnLine(6, propertyisDuplicate); - expect(diagnostics.length).toBe(1); - expect(diagnostics[0].message).toBe(test1Message); - }); - - test('line 7', () => { - const test1Message = 'Property "array" is already declared.'; - const diagnostics = utils.diagnosticsOnLine(7, propertyisDuplicate); - expect(diagnostics.length).toBe(1); - expect(diagnostics[0].message).toBe(test1Message); - }); - - test('line 8', () => { - const test1Message = 'Property "aRRay" is already declared with different case.'; - const diagnostics = utils.diagnosticsOnLine(8, propertyisDuplicate); - expect(diagnostics.length).toBe(1); - expect(diagnostics[0].message).toBe(test1Message); - }); - - test('line 9', () => { - const test1Message = 'Property "array" is already declared.'; - const diagnostics = utils.diagnosticsOnLine(9, propertyisDuplicate); - expect(diagnostics.length).toBe(1); - expect(diagnostics[0].message).toBe(test1Message); - }); - - test('line 10', () => { - const test1Message = 'Property "array" is already declared.'; - const diagnostics = utils.diagnosticsOnLine(10, propertyisDuplicate); - expect(diagnostics.length).toBe(1); - expect(diagnostics[0].message).toBe(test1Message); - }); - - test('line 11', () => { - const diagnostics = utils.diagnosticsOnLine(11, propertyisDuplicate); - expect(diagnostics.length).toBe(0); - }); - - test('line 12', () => { - const test1Message = 'Property "customer" is already declared.'; - const diagnostics = utils.diagnosticsOnLine(12, propertyisDuplicate); - expect(diagnostics.length).toBe(1); - expect(diagnostics[0].message).toBe(test1Message); - }); - - test('line 13', () => { - const test1Message = 'Property "inliteral" is already declared with different case.'; - const diagnostics = utils.diagnosticsOnLine(13, propertyisDuplicate); - expect(diagnostics.length).toBe(1); - expect(diagnostics[0].message).toBe(test1Message); - }); - -}); diff --git a/__tests__/files/ZDuplicateProperty.PROC b/__tests__/files/ZDuplicateProperty.PROC deleted file mode 100644 index 400520e..0000000 --- a/__tests__/files/ZDuplicateProperty.PROC +++ /dev/null @@ -1,14 +0,0 @@ - #CLASSDEF public - #PROPERTYDEF customer class = Number position = 2 private - #PROPERTYDEF account class = Integer position = 3 private - #PROPERTYDEF aCCount class = Number position = 4 private - #PROPERTYDEF accounT class = Number position = 5 private - #PROPERTYDEF array class=String private node="account1" - #PROPERTYDEF customer class = Number position = 6 private - #PROPERTYDEF array class=String private node="account2" - #PROPERTYDEF aRRay class=String private node="array2" - #PROPERTYDEF array class=String private node="array2" - #PROPERTYDEF array class=String private node="array2" - #PROPERTYDEF INLITERAL = 0 class=Integer public literal - #PROPERTYDEF customer class = Number position = 7 private - #PROPERTYDEF inliteral class = Number position = 8 private \ No newline at end of file diff --git a/__tests__/files/ZMethodDoc.PROC b/__tests__/files/ZMethodDoc.PROC deleted file mode 100644 index b9dfad8..0000000 --- a/__tests__/files/ZMethodDoc.PROC +++ /dev/null @@ -1,34 +0,0 @@ -public void allProblemsNoLineAbove() - quit -public void allProblems() - quit - // ------------------------------------------------------------------- -public void onlySeparator() - quit - - // ------------------------------------------------------------------- -public void oneLineSeparator() - quit - - - // ------------------------------------------------------------------- -public void twoLineSeparator() - quit -public void onlyDoc() - /* DOC */ - quit - -public void oneLineDoc() - /* DOC */ - quit - - -public void twoLineDoc() - /* DOC */ - quit - - - // ------------------------------------------------------------------- -public void withEverything() - /* DOC */ - quit diff --git a/__tests__/files/ZMultiLineDeclare.PROC b/__tests__/files/ZMultiLineDeclare.PROC deleted file mode 100644 index 1afb58f..0000000 --- a/__tests__/files/ZMultiLineDeclare.PROC +++ /dev/null @@ -1,16 +0,0 @@ -public static void ZTEST() - type Number test1, test2 = "" - type Number number1, number2 = "" - type ResultSet rs1, rs2, rs3 = "" - type void x(String) - type Number number11="", number13, number15="" - type Number number19, number20=1, number21, number22=0, number23 - type Number number29, number30 - type Number number32, number34(), number36 = 0 - type Number number37=(((%PG-1)*15)+1), number38=(((%PG-1)*15)+1) - type ResultSet rs4 = Db.select("ACN", "I999GLAD", "IBAN = :tba.iban"), rs5= Db.select("ACN", "I999GLAD", "IBAN = :tba.iban") - type Number number38 = rs4.getCol("CID"), number39 = rs4.getCol("CID") - type Number number40 = $$getTotAuthOdLimit^RecordDEPAUTHODLIMIT(dep.cid), number41 = $$getTotAuthOdLimit^RecordDEPAUTHODLIMIT(dep.cid) - type Number number42=ln("ACN").toNumber(),number41=ln("BOO").toNumber(),number43=ln("TYPE").toNumber() - type String test=this.test12 - quit \ No newline at end of file diff --git a/__tests__/files/ZRuntime.PROC b/__tests__/files/ZRuntime.PROC deleted file mode 100644 index babc1c0..0000000 --- a/__tests__/files/ZRuntime.PROC +++ /dev/null @@ -1,54 +0,0 @@ - #PACKAGE custom - #CLASSDEF public - -public static void func(String flaggedParam, String notFlaggedParam) - - type String flagged - type String notFlagged - - // no flag - do Runtime.start("BA") - do Runtime.commit() - - // flag for flagged - do Runtime.start("BA") - set flagged = "" - do Runtime.commit() - - // flag for flagged and not notFlagged - do Runtime.start("BA", "notFlagged") - set flagged = "" - set notFlagged = "" - do Runtime.commit() - - // @psl-lint.RuntimeStart accept="notFlagged" - do Runtime.start("BA") - set notFlagged = "" - do Runtime.commit() - - // no flag - do Runtime.start("BA") - type String declaredInside - set declaredInside = "" - do Runtime.commit() - - // flag flaggedParam - do Runtime.start("BA", "notFlaggedParam") - set flaggedParam = "" - set notFlaggedParam = "" - do Runtime.commit() - - // flag notFlaggedTwice once, along with relatedDiagnostics - type String notFlaggedTwice = "" - do Runtime.start("BA") - set notFlaggedTwice = "" - do Runtime.commit() - do Runtime.commit() - - type String literal NOLITERAL = "" - // flag flagged but not NOLITERAL - do Runtime.start("BA") - set (flagged, NOLITERAL) = "" - do Runtime.commit() - - quit diff --git a/__tests__/files/ZTblColDocTst-Col1.COL b/__tests__/files/ZTblColDocTst-Col1.COL deleted file mode 100644 index 96abc00..0000000 --- a/__tests__/files/ZTblColDocTst-Col1.COL +++ /dev/null @@ -1,43 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst", - "DI" : "Col1", - "ALIAS" : "HoldAutoallyPlaced", - "CMP" : null, - "CMPFUNCUDF" : false, - "CNV" : null, - "DEC" : null, - "DEPOSTP" : null, - "DEPREP" : null, - "DES" : "Test for COL Documentation", - "DFT" : "0", - "DOM" : null, - "ISCUSTOM" : false, - "ISMASTER" : false, - "LEN" : 1, - "MAX" : null, - "MDD" : null, - "MIN" : null, - "NOD" : "KEY", - "NULLIND" : false, - "POS" : 30, - "PTN" : null, - "RDBPOS" : null, - "RDBTBL" : null, - "REQ" : true, - "RHD" : "Test for COL Documentation", - "SFD" : null, - "SIZ" : 1, - "SRL" : false, - "TBL" : null, - "TYP" : "L", - "VAL4EXT" : false, - "XPO" : null, - "XPR" : null -} -An option that indicates whether a permanent hold should be applied for -a payment order. If this option is selected, the payment order amount -holds for the number of days specified in the Max Hold Days field -{CTBLEFTTYPE.HLDMAX}. - -This option is only valid for outgoing payments. diff --git a/__tests__/files/ZTblColDocTst-Col2.COL b/__tests__/files/ZTblColDocTst-Col2.COL deleted file mode 100644 index f3fedb8..0000000 --- a/__tests__/files/ZTblColDocTst-Col2.COL +++ /dev/null @@ -1,42 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst", - "DI" : "Col2", - "ALIAS" : "HoldAutoallyPlaced", - "CMP" : null, - "CMPFUNCUDF" : false, - "CNV" : null, - "DEC" : null, - "DEPOSTP" : null, - "DEPREP" : null, - "DES" : "Test for COL Documentation", - "DFT" : "0", - "DOM" : null, - "ISCUSTOM" : false, - "ISMASTER" : false, - "LEN" : 1, - "MAX" : null, - "MDD" : null, - "MIN" : null, - "NOD" : "KEY", - "NULLIND" : false, - "POS" : 30, - "PTN" : null, - "RDBPOS" : null, - "RDBTBL" : null, - "REQ" : true, - "RHD" : "Test for COL Documentation", - "SFD" : null, - "SIZ" : 1, - "SRL" : false, - "TBL" : null, - "TYP" : "L", - "VAL4EXT" : false, - "XPO" : null, - "XPR" : null -} -An option that indicates whether a permanent hold should be applied for -a payment order. If this option is selected, the payment order amount -holds for the number of days specified in the Max Hold Days field. - -This option is only valid for outgoing payments. diff --git a/__tests__/files/ZTblColDocTst-Col3.COL b/__tests__/files/ZTblColDocTst-Col3.COL deleted file mode 100644 index 5533117..0000000 --- a/__tests__/files/ZTblColDocTst-Col3.COL +++ /dev/null @@ -1,37 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst", - "DI" : "Col3", - "ALIAS" : "HoldAutoallyPlaced", - "CMP" : null, - "CMPFUNCUDF" : false, - "CNV" : null, - "DEC" : null, - "DEPOSTP" : null, - "DEPREP" : null, - "DES" : "Test for COL definition without documentation", - "DFT" : "0", - "DOM" : null, - "ISCUSTOM" : false, - "ISMASTER" : false, - "LEN" : 1, - "MAX" : null, - "MDD" : null, - "MIN" : null, - "NOD" : "KEY", - "NULLIND" : false, - "POS" : 30, - "PTN" : null, - "RDBPOS" : null, - "RDBTBL" : null, - "REQ" : true, - "RHD" : "Test for COL definition without documentation", - "SFD" : null, - "SIZ" : 1, - "SRL" : false, - "TBL" : null, - "TYP" : "L", - "VAL4EXT" : false, - "XPO" : null, - "XPR" : null -} \ No newline at end of file diff --git a/__tests__/files/ZTblColDocTst-Col4.COL b/__tests__/files/ZTblColDocTst-Col4.COL deleted file mode 100644 index b7a451b..0000000 --- a/__tests__/files/ZTblColDocTst-Col4.COL +++ /dev/null @@ -1,41 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst", - "DI" : "Col4", - "ALIAS" : "HoldAutoallyPlaced", - "CMP" : null, - "CMPFUNCUDF" : false, - "CNV" : null, - "DEC" : null, - "DEPOSTP" : null, - "DEPREP" : null, - "DES" : "Test for COL definition without documentation but extra space at the end", - "DFT" : "0", - "DOM" : null, - "ISCUSTOM" : false, - "ISMASTER" : false, - "LEN" : 1, - "MAX" : null, - "MDD" : null, - "MIN" : null, - "NOD" : "KEY", - "NULLIND" : false, - "POS" : 30, - "PTN" : null, - "RDBPOS" : null, - "RDBTBL" : null, - "REQ" : true, - "RHD" : "Test for COL definition without documentation but extra space at the end", - "SFD" : null, - "SIZ" : 1, - "SRL" : false, - "TBL" : null, - "TYP" : "L", - "VAL4EXT" : false, - "XPO" : null, - "XPR" : null -} - - - - diff --git a/__tests__/files/ZTblColDocTst-Col5.COL b/__tests__/files/ZTblColDocTst-Col5.COL deleted file mode 100644 index b0bbc08..0000000 --- a/__tests__/files/ZTblColDocTst-Col5.COL +++ /dev/null @@ -1,42 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst", - "DI" : "Col5", - "ALIAS" : "HoldAutoallyPlaced", - "CMP" : null, - "CMPFUNCUDF" : false, - "CNV" : null, - "DEC" : null, - "DEPOSTP" : null, - "DEPREP" : null, - "DES" : "Test for COL Documentation with { and } in the definition", - "DFT" : "0", - "DOM" : null, - "ISCUSTOM" : false, - "ISMASTER" : false, - "LEN" : 1, - "MAX" : null, - "MDD" : null, - "MIN" : null, - "NOD" : "KEY", - "NULLIND" : false, - "POS" : 30, - "PTN" : null, - "RDBPOS" : null, - "RDBTBL" : null, - "REQ" : true, - "RHD" : "Test for COL Documentation with { and } in the definition", - "SFD" : null, - "SIZ" : 1, - "SRL" : false, - "TBL" : null, - "TYP" : "L", - "VAL4EXT" : false, - "XPO" : null, - "XPR" : null -} -An option that indicates whether a permanent hold should be applied for -a payment order. If this option is selected, the payment order amount -holds for the number of days specified in the Max Hold Days field. - -This option is only valid for outgoing payments. diff --git a/__tests__/files/ZTblColDocTst-Col6.COL b/__tests__/files/ZTblColDocTst-Col6.COL deleted file mode 100644 index a9d78c0..0000000 --- a/__tests__/files/ZTblColDocTst-Col6.COL +++ /dev/null @@ -1,37 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst", - "DI" : "Col6", - "ALIAS" : "HoldAutoallyPlaced", - "CMP" : null, - "CMPFUNCUDF" : false, - "CNV" : null, - "DEC" : null, - "DEPOSTP" : null, - "DEPREP" : null, - "DES" : "{Test for COL Documentation}", - "DFT" : "0", - "DOM" : null, - "ISCUSTOM" : false, - "ISMASTER" : false, - "LEN" : 1, - "MAX" : null, - "MDD" : null, - "MIN" : null, - "NOD" : "KEY", - "NULLIND" : false, - "POS" : 30, - "PTN" : null, - "RDBPOS" : null, - "RDBTBL" : null, - "REQ" : true, - "RHD" : "{Test for COL Documentation}", - "SFD" : null, - "SIZ" : 1, - "SRL" : false, - "TBL" : null, - "TYP" : "L", - "VAL4EXT" : false, - "XPO" : null, - "XPR" : null - diff --git a/__tests__/files/ZTblColDocTst1.TBL b/__tests__/files/ZTblColDocTst1.TBL deleted file mode 100644 index e3c5e25..0000000 --- a/__tests__/files/ZTblColDocTst1.TBL +++ /dev/null @@ -1,43 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst1", - "ACCKEYS" : "CID", - "ALIAS" : "Deposit", - "CACHED" : 1, - "DEL" : 124, - "DES" : "Deposit File", - "DFLAG" : false, - "DFTDES" : "CID/LE=15/RH=Account Number,LNM,CLS/LE=4/RH=CLS,GRP/LE=5/RH=Group,TYPE/LE=12", - "DFTDES1" : null, - "DFTHDR" : null, - "DFTORD" : false, - "EXIST" : 50, - "EXTENDLENGTH" : false, - "FILETYP" : 1, - "FPN" : "ZTblColDocTst1", - "FSN" : "ZTblColDocTst1", - "GLOBAL" : "ACN", - "GLREF" : "^ACN(CID", - "LOG" : false, - "MPLCTDD" : null, - "PARFID" : "ACN", - "PREDAEN" : null, - "PSLPACKAGE" : null, - "PSLRESTRICTION" : null, - "PTRTIM" : null, - "PTRTIMU" : null, - "PTRTLD" : "FMLD", - "PTRTLDU" : "FMLD", - "PTRUSER" : null, - "PTRUSERU" : null, - "QID1" : "CLS=\"D\"", - "RECTYP" : 10, - "RFLAG" : false, - "SCREEN" : null, - "SQLRESTRICTION" : null, - "SYSSN" : "PBS", - "UDPOST" : null, - "UDPRE" : "^DEPVER", - "VAL4EXT" : false -} -Test table documentation with { and } braces \ No newline at end of file diff --git a/__tests__/files/ZTblColDocTst2.TBL b/__tests__/files/ZTblColDocTst2.TBL deleted file mode 100644 index bce012f..0000000 --- a/__tests__/files/ZTblColDocTst2.TBL +++ /dev/null @@ -1,43 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst2", - "ACCKEYS" : "CID", - "ALIAS" : "Deposit", - "CACHED" : 1, - "DEL" : 124, - "DES" : "Deposit File", - "DFLAG" : false, - "DFTDES" : "CID/LE=15/RH=Account Number,LNM,CLS/LE=4/RH=CLS,GRP/LE=5/RH=Group,TYPE/LE=12", - "DFTDES1" : null, - "DFTHDR" : null, - "DFTORD" : false, - "EXIST" : 50, - "EXTENDLENGTH" : false, - "FILETYP" : 1, - "FPN" : "ZTblColDocTst2", - "FSN" : "ZTblColDocTst2", - "GLOBAL" : "ACN", - "GLREF" : "^ACN(CID", - "LOG" : false, - "MPLCTDD" : null, - "PARFID" : "ACN", - "PREDAEN" : null, - "PSLPACKAGE" : null, - "PSLRESTRICTION" : null, - "PTRTIM" : null, - "PTRTIMU" : null, - "PTRTLD" : "FMLD", - "PTRTLDU" : "FMLD", - "PTRUSER" : null, - "PTRUSERU" : null, - "QID1" : "CLS=\"D\"", - "RECTYP" : 10, - "RFLAG" : false, - "SCREEN" : null, - "SQLRESTRICTION" : null, - "SYSSN" : "PBS", - "UDPOST" : null, - "UDPRE" : "^DEPVER", - "VAL4EXT" : false -} -Test table documentation \ No newline at end of file diff --git a/__tests__/files/ZTblColDocTst3.TBL b/__tests__/files/ZTblColDocTst3.TBL deleted file mode 100644 index 96b166a..0000000 --- a/__tests__/files/ZTblColDocTst3.TBL +++ /dev/null @@ -1,42 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst3", - "ACCKEYS" : "CID", - "ALIAS" : "Deposit", - "CACHED" : 1, - "DEL" : 124, - "DES" : "Test Table Definition without documentation", - "DFLAG" : false, - "DFTDES" : "CID/LE=15/RH=Account Number,LNM,CLS/LE=4/RH=CLS,GRP/LE=5/RH=Group,TYPE/LE=12", - "DFTDES1" : null, - "DFTHDR" : null, - "DFTORD" : false, - "EXIST" : 50, - "EXTENDLENGTH" : false, - "FILETYP" : 1, - "FPN" : "ZTblColDocTst3", - "FSN" : "ZTblColDocTst3", - "GLOBAL" : "ACN", - "GLREF" : "^ACN(CID", - "LOG" : false, - "MPLCTDD" : null, - "PARFID" : "ACN", - "PREDAEN" : null, - "PSLPACKAGE" : null, - "PSLRESTRICTION" : null, - "PTRTIM" : null, - "PTRTIMU" : null, - "PTRTLD" : "FMLD", - "PTRTLDU" : "FMLD", - "PTRUSER" : null, - "PTRUSERU" : null, - "QID1" : "CLS=\"D\"", - "RECTYP" : 10, - "RFLAG" : false, - "SCREEN" : null, - "SQLRESTRICTION" : null, - "SYSSN" : "PBS", - "UDPOST" : null, - "UDPRE" : "^DEPVER", - "VAL4EXT" : false -} \ No newline at end of file diff --git a/__tests__/files/ZTblColDocTst4.TBL b/__tests__/files/ZTblColDocTst4.TBL deleted file mode 100644 index c3f0791..0000000 --- a/__tests__/files/ZTblColDocTst4.TBL +++ /dev/null @@ -1,46 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst4", - "ACCKEYS" : "CID", - "ALIAS" : "Deposit", - "CACHED" : 1, - "DEL" : 124, - "DES" : "Test Table Definition without documentation but extra space at the end", - "DFLAG" : false, - "DFTDES" : "CID/LE=15/RH=Account Number,LNM,CLS/LE=4/RH=CLS,GRP/LE=5/RH=Group,TYPE/LE=12", - "DFTDES1" : null, - "DFTHDR" : null, - "DFTORD" : false, - "EXIST" : 50, - "EXTENDLENGTH" : false, - "FILETYP" : 1, - "FPN" : "ZTblColDocTst4", - "FSN" : "ZTblColDocTst4", - "GLOBAL" : "ACN", - "GLREF" : "^ACN(CID", - "LOG" : false, - "MPLCTDD" : null, - "PARFID" : "ACN", - "PREDAEN" : null, - "PSLPACKAGE" : null, - "PSLRESTRICTION" : null, - "PTRTIM" : null, - "PTRTIMU" : null, - "PTRTLD" : "FMLD", - "PTRTLDU" : "FMLD", - "PTRUSER" : null, - "PTRUSERU" : null, - "QID1" : "CLS=\"D\"", - "RECTYP" : 10, - "RFLAG" : false, - "SCREEN" : null, - "SQLRESTRICTION" : null, - "SYSSN" : "PBS", - "UDPOST" : null, - "UDPRE" : "^DEPVER", - "VAL4EXT" : false -} - - - - diff --git a/__tests__/files/ZTblColDocTst5.TBL b/__tests__/files/ZTblColDocTst5.TBL deleted file mode 100644 index 7833114..0000000 --- a/__tests__/files/ZTblColDocTst5.TBL +++ /dev/null @@ -1,43 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst5", - "ACCKEYS" : "CID", - "ALIAS" : "Deposit", - "CACHED" : 1, - "DEL" : 124, - "DES" : "Test table documentation with { and } inside the definition.", - "DFLAG" : false, - "DFTDES" : "CID/LE=15/RH=Account Number,LNM,CLS/LE=4/RH=CLS,GRP/LE=5/RH=Group,TYPE/LE=12", - "DFTDES1" : null, - "DFTHDR" : null, - "DFTORD" : false, - "EXIST" : 50, - "EXTENDLENGTH" : false, - "FILETYP" : 1, - "FPN" : "ZTblColDocTst5", - "FSN" : "ZTblColDocTst5", - "GLOBAL" : "ACN", - "GLREF" : "^ACN(CID", - "LOG" : false, - "MPLCTDD" : null, - "PARFID" : "ACN", - "PREDAEN" : null, - "PSLPACKAGE" : null, - "PSLRESTRICTION" : null, - "PTRTIM" : null, - "PTRTIMU" : null, - "PTRTLD" : "FMLD", - "PTRTLDU" : "FMLD", - "PTRUSER" : null, - "PTRUSERU" : null, - "QID1" : "CLS=\"D\"", - "RECTYP" : 10, - "RFLAG" : false, - "SCREEN" : null, - "SQLRESTRICTION" : null, - "SYSSN" : "PBS", - "UDPOST" : null, - "UDPRE" : "^DEPVER", - "VAL4EXT" : false -} -Test table documentation with { and } inside the definition. \ No newline at end of file diff --git a/__tests__/files/ZTblColDocTst6.TBL b/__tests__/files/ZTblColDocTst6.TBL deleted file mode 100644 index b9e80d8..0000000 --- a/__tests__/files/ZTblColDocTst6.TBL +++ /dev/null @@ -1,41 +0,0 @@ -{ - "%LIBS" : "SYSDEV", - "FID" : "ZTblColDocTst6", - "ACCKEYS" : "CID", - "ALIAS" : "Deposit", - "CACHED" : 1, - "DEL" : 124, - "DES" : "Test table documentation with { and } inside the definition.", - "DFLAG" : false, - "DFTDES" : "CID/LE=15/RH=Account Number,LNM,CLS/LE=4/RH=CLS,GRP/LE=5/RH=Group,TYPE/LE=12", - "DFTDES1" : null, - "DFTHDR" : null, - "DFTORD" : false, - "EXIST" : 50, - "EXTENDLENGTH" : false, - "FILETYP" : 1, - "FPN" : "ZTblColDocTst6", - "FSN" : "ZTblColDocTst6", - "GLOBAL" : "ACN", - "GLREF" : "^ACN(CID", - "LOG" : false, - "MPLCTDD" : null, - "PARFID" : "ACN", - "PREDAEN" : null, - "PSLPACKAGE" : null, - "PSLRESTRICTION" : null, - "PTRTIM" : null, - "PTRTIMU" : null, - "PTRTLD" : "FMLD", - "PTRTLDU" : "FMLD", - "PTRUSER" : null, - "PTRUSERU" : null, - "QID1" : "CLS=\"D\"", - "RECTYP" : 10, - "RFLAG" : false, - "SCREEN" : null, - "SQLRESTRICTION" : null, - "SYSSN" : "PBS", - "UDPOST" : null, - "UDPRE" : "^DEPVER", - "VAL4EXT" : false diff --git a/__tests__/files/ZTestConvention.PROC b/__tests__/files/ZTestConvention.PROC deleted file mode 100644 index 5200b05..0000000 --- a/__tests__/files/ZTestConvention.PROC +++ /dev/null @@ -1,26 +0,0 @@ - #CLASSDEF extends = ZParent - - #PROPERTYDEF dummy class = String position = 2 - #PROPERTYDEF propInParentAndChild class = String position = 3 - #PROPERTYDEF PROPINCHILD class = String position = 4 - #PROPERTYDEF detailFile = "B32572" class = String private literal - /* DOC ---------------------------------------------------------------- - header file name - ** ENDDOC */ - // -------------------------------------------------------------------- -public void String zebraMethod() - /* DOC ---------------------------------------------------------------- - BLABLA - ** ENDDOC */ - type Number thisNumberHasMoreThanTwentyFiveCharacters - quit - // -------------------------------------------------------------------- -private void String methodInChild() - /* DOC ---------------------------------------------------------------- - BLABLABLABLA - - ** ENDDOC */ - type String y - type String vString - type public Number vNumber - quit diff --git a/__tests__/files/ZTestParams.PROC b/__tests__/files/ZTestParams.PROC deleted file mode 100644 index a2755bd..0000000 --- a/__tests__/files/ZTestParams.PROC +++ /dev/null @@ -1,40 +0,0 @@ - - // -------------------------------------------------------------------- -public static void f0() - - quit - - // -------------------------------------------------------------------- -public static void f1(Number a1) - - quit - - // -------------------------------------------------------------------- -public static void f2(Number a1, Number a2) - - quit - - // -------------------------------------------------------------------- -f3(Number a1, Number a2, Number a3) - - quit - - // -------------------------------------------------------------------- -f4(Number a1, Number a2, Number a3, a4) - - quit - - // -------------------------------------------------------------------- -f6(Number a1, Number a2(String)) - - quit - - // -------------------------------------------------------------------- -f7(Number a1, Number a2()) - - quit - - // -------------------------------------------------------------------- -f8(Number a1, Number a2(,,)) - - quit diff --git a/__tests__/methodDoc-test.ts b/__tests__/methodDoc-test.ts deleted file mode 100644 index 2b775bc..0000000 --- a/__tests__/methodDoc-test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import * as api from '../src/pslLint/api'; -import { MethodDocumentation, MethodSeparator, TwoEmptyLines } from '../src/pslLint/methodDoc'; -import * as utils from './ruleUtils'; - -function messageOnLine(lineNumber: number, allDiagnostics: api.Diagnostic[]): string { - const diagnosticsOnLine = utils.diagnosticsOnLine(lineNumber, allDiagnostics); - if (!diagnosticsOnLine.length) return ''; - return diagnosticsOnLine[0].message; -} - -describe('Parameter tests', () => { - const procName = 'ZMethodDoc.PROC'; - let docDiagnostics: api.Diagnostic[] = []; - let emptyLineDiagnostics: api.Diagnostic[] = []; - let separatorDiagnostics: api.Diagnostic[] = []; - - beforeAll(async () => { - docDiagnostics = await utils.getDiagnostics(procName, MethodDocumentation.name); - emptyLineDiagnostics = await utils.getDiagnostics(procName, TwoEmptyLines.name); - separatorDiagnostics = await utils.getDiagnostics(procName, MethodSeparator.name); - }); - - test('allProblemsNoLineAbove', () => { - expect(messageOnLine(0, docDiagnostics)).toBe(`Documentation missing for label "allProblemsNoLineAbove".`); - expect(messageOnLine(0, separatorDiagnostics)).toBe(`Separator missing for label "allProblemsNoLineAbove".`); - expect(messageOnLine(0, emptyLineDiagnostics)).toBe( - `There should be two empty lines above label "allProblemsNoLineAbove".` - ); - }); - test('allProblems', () => { - expect(messageOnLine(2, docDiagnostics)).toBe(`Documentation missing for label "allProblems".`); - expect(messageOnLine(2, separatorDiagnostics)).toBe(`Separator missing for label "allProblems".`); - expect(messageOnLine(2, emptyLineDiagnostics)).toBe(`There should be two empty lines above label "allProblems".`); - }); - test('onlySeparator', () => { - expect(messageOnLine(5, docDiagnostics)).toBe(`Documentation missing for label "onlySeparator".`); - expect(messageOnLine(5, separatorDiagnostics)).toBe(''); - expect(messageOnLine(5, emptyLineDiagnostics)).toBe(`There should be two empty lines above label "onlySeparator".`); - }); - test('twoLineSeparator', () => { - expect(messageOnLine(14, docDiagnostics)).toBe(`Documentation missing for label "twoLineSeparator".`); - expect(messageOnLine(14, separatorDiagnostics)).toBe(''); - expect(messageOnLine(14, emptyLineDiagnostics)).toBe(''); - }); - test('onlyDoc', () => { - expect(messageOnLine(16, docDiagnostics)).toBe(''); - expect(messageOnLine(16, separatorDiagnostics)).toBe(`Separator missing for label "onlyDoc".`); - expect(messageOnLine(16, emptyLineDiagnostics)).toBe(`There should be two empty lines above label "onlyDoc".`); - }); - test('oneLineDoc', () => { - expect(messageOnLine(20, docDiagnostics)).toBe(''); - expect(messageOnLine(20, separatorDiagnostics)).toBe(`Separator missing for label "oneLineDoc".`); - expect(messageOnLine(20, emptyLineDiagnostics)).toBe(`There should be two empty lines above label "oneLineDoc".`); - }); - test('twoLineDoc', () => { - expect(messageOnLine(25, docDiagnostics)).toBe(''); - expect(messageOnLine(25, separatorDiagnostics)).toBe(`Separator missing for label "twoLineDoc".`); - expect(messageOnLine(25, emptyLineDiagnostics)).toBe(''); - }); - test('withEverything', () => { - expect(messageOnLine(31, docDiagnostics)).toBe(''); - expect(messageOnLine(31, separatorDiagnostics)).toBe(''); - expect(messageOnLine(31, emptyLineDiagnostics)).toBe(''); - }); -}); diff --git a/__tests__/multiLineDeclare-test.ts b/__tests__/multiLineDeclare-test.ts deleted file mode 100644 index 9e8249c..0000000 --- a/__tests__/multiLineDeclare-test.ts +++ /dev/null @@ -1,136 +0,0 @@ -import * as api from '../src/pslLint/api'; -import { MultiLineDeclare } from '../src/pslLint/multiLineDeclare'; -import * as utils from './ruleUtils'; - -describe('Parameter tests', () => { - - let multiLineDiagnostics: api.Diagnostic[] = []; - - beforeAll(async () => { - multiLineDiagnostics = await utils.getDiagnostics('ZMultiLineDeclare.PROC', MultiLineDeclare.name); - }); - - test('line 2', () => { - const test1Message = 'Declaration test1 should be initialized on a new line.'; - const test2Message = 'Declaration test2 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(1, multiLineDiagnostics); - expect(diagnostics.length).toBe(2); - expect(diagnostics[0].message).toBe(test1Message); - expect(diagnostics[1].message).toBe(test2Message); - }); - - test('line 3', () => { - const number1Message = 'Declaration number1 should be initialized on a new line.'; - const number2Message = 'Declaration number2 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(2, multiLineDiagnostics); - expect(diagnostics.length).toBe(2); - expect(diagnostics[0].message).toBe(number1Message); - expect(diagnostics[1].message).toBe(number2Message); - }); - - test('line 4', () => { - const rs1Message = 'Declaration rs1 should be initialized on a new line.'; - const rs2Message = 'Declaration rs2 should be initialized on a new line.'; - const rs3Message = 'Declaration rs3 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(3, multiLineDiagnostics); - expect(diagnostics.length).toBe(3); - expect(diagnostics[0].message).toBe(rs1Message); - expect(diagnostics[1].message).toBe(rs2Message); - expect(diagnostics[2].message).toBe(rs3Message); - }); - - test('line 5', () => { - const diagnostics = utils.diagnosticsOnLine(4, multiLineDiagnostics); - expect(diagnostics.length).toBe(0); - }); - - test('line 6', () => { - const number11Message = 'Declaration number11 should be initialized on a new line.'; - const number13Message = 'Declaration number13 should be initialized on a new line.'; - const number15Message = 'Declaration number15 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(5, multiLineDiagnostics); - expect(diagnostics.length).toBe(3); - expect(diagnostics[0].message).toBe(number11Message); - expect(diagnostics[1].message).toBe(number13Message); - expect(diagnostics[2].message).toBe(number15Message); - }); - - test('line 7', () => { - const number19Message = 'Declaration number19 should be initialized on a new line.'; - const number20Message = 'Declaration number20 should be initialized on a new line.'; - const number21Message = 'Declaration number21 should be initialized on a new line.'; - const number22Message = 'Declaration number22 should be initialized on a new line.'; - const number23Message = 'Declaration number23 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(6, multiLineDiagnostics); - expect(diagnostics.length).toBe(5); - expect(diagnostics[0].message).toBe(number19Message); - expect(diagnostics[1].message).toBe(number20Message); - expect(diagnostics[2].message).toBe(number21Message); - expect(diagnostics[3].message).toBe(number22Message); - expect(diagnostics[4].message).toBe(number23Message); - }); - - test('line 8', () => { - const diagnostics = utils.diagnosticsOnLine(7, multiLineDiagnostics); - expect(diagnostics.length).toBe(0); - }); - - test('line 9', () => { - const number32Message = 'Declaration number32 should be initialized on a new line.'; - const number34Message = 'Declaration number34 should be initialized on a new line.'; - const number36Message = 'Declaration number36 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(8, multiLineDiagnostics); - expect(diagnostics.length).toBe(3); - expect(diagnostics[0].message).toBe(number32Message); - expect(diagnostics[1].message).toBe(number34Message); - expect(diagnostics[2].message).toBe(number36Message); - }); - - test('line 10', () => { - const number37Message = 'Declaration number37 should be initialized on a new line.'; - const number38Message = 'Declaration number38 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(9, multiLineDiagnostics); - expect(diagnostics.length).toBe(2); - expect(diagnostics[0].message).toBe(number37Message); - expect(diagnostics[1].message).toBe(number38Message); - }); - - test('line 11', () => { - const rs4Message = 'Declaration rs4 should be initialized on a new line.'; - const rs5Message = 'Declaration rs5 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(10, multiLineDiagnostics); - expect(diagnostics.length).toBe(2); - expect(diagnostics[0].message).toBe(rs4Message); - expect(diagnostics[1].message).toBe(rs5Message); - }); - - test('line 12', () => { - const number38Message = 'Declaration number38 should be initialized on a new line.'; - const number39Message = 'Declaration number39 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(11, multiLineDiagnostics); - expect(diagnostics.length).toBe(2); - expect(diagnostics[0].message).toBe(number38Message); - expect(diagnostics[1].message).toBe(number39Message); - }); - - test('line 13', () => { - const number40Message = 'Declaration number40 should be initialized on a new line.'; - const number41Message = 'Declaration number41 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(12, multiLineDiagnostics); - expect(diagnostics.length).toBe(2); - expect(diagnostics[0].message).toBe(number40Message); - expect(diagnostics[1].message).toBe(number41Message); - }); - - test('line 14', () => { - const number42Message = 'Declaration number42 should be initialized on a new line.'; - const number41Message = 'Declaration number41 should be initialized on a new line.'; - const number43Message = 'Declaration number43 should be initialized on a new line.'; - const diagnostics = utils.diagnosticsOnLine(13, multiLineDiagnostics); - expect(diagnostics.length).toBe(3); - expect(diagnostics[0].message).toBe(number42Message); - expect(diagnostics[1].message).toBe(number41Message); - expect(diagnostics[2].message).toBe(number43Message); - }); - -}); diff --git a/__tests__/parameters-test.ts b/__tests__/parameters-test.ts deleted file mode 100644 index e0f907d..0000000 --- a/__tests__/parameters-test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { MethodParametersOnNewLine } from '../src/pslLint/parameters'; -import * as api from '../src/pslLint/api'; -import * as utils from './ruleUtils'; - -describe('Parameter tests', () => { - - let parametersReport: api.Diagnostic[] = []; - - beforeAll(async () => { - parametersReport = await utils.getDiagnostics('ZTestParams.PROC', MethodParametersOnNewLine.name); - }) - - test('No report for no params', () => { - expect(utils.diagnosticsOnLine(2, parametersReport).length).toBe(0) - }) - - test('No report for one param on same line', () => { - expect(utils.diagnosticsOnLine(7, parametersReport).length).toBe(0) - }) - - test('Two reports for two params', () => { - expect(utils.diagnosticsOnLine(12, parametersReport).length).toBe(2) - }) - - test('Catch label', () => { - expect(utils.diagnosticsOnLine(17, parametersReport).length).toBe(3) - }) - - test('Catch no types on params', () => { - expect(utils.diagnosticsOnLine(22, parametersReport).length).toBe(4) - }) - - test('Catch tree', () => { - expect(utils.diagnosticsOnLine(27, parametersReport).length).toBe(2) - }) - - test('Catch tree with empty parens', () => { - expect(utils.diagnosticsOnLine(32, parametersReport).length).toBe(2) - }) - - test('Catch tree with empty parens and commas', () => { - expect(utils.diagnosticsOnLine(37, parametersReport).length).toBe(2) - }) -}) diff --git a/__tests__/ruleUtils.ts b/__tests__/ruleUtils.ts deleted file mode 100644 index 79dbd3a..0000000 --- a/__tests__/ruleUtils.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as fs from 'fs-extra'; -import * as path from 'path'; -import { parseText } from '../src/parser/parser'; -import * as activate from '../src/pslLint/activate'; -import * as api from '../src/pslLint/api'; - -/** - * Returns the specific diagnostics on a given line - * - * @param lineNumber Zero-based line number to check, i.e. line 1 of the document is lineNumber 0. - * @param diagnostics The reports to filter - */ -export function diagnosticsOnLine(lineNumber: number, diagnostics: api.Diagnostic[]): api.Diagnostic[] { - const lineDiagnostics = diagnostics.filter(r => r.range.start.line === lineNumber); - return lineDiagnostics; -} - -/** - * Gets the diagnostics for the given file. - * - * @param testFileName The name of the file located in `${PROJECT_ROOT}/__tests__/files/` - * @param ruleName Optional parameter to return only diagnostics corresponding to the ruleName - */ -export async function getDiagnostics(testFileName: string, ruleName?: string): Promise { - const testFilePath = path.resolve('__tests__', 'files', testFileName); - const text = await fs.readFile(testFilePath).then(b => b.toString()); - - const profileComponent = new api.ProfileComponent(testFilePath, text); - const diagnostics = activate.getDiagnostics(profileComponent, parseText(text), false); - if (ruleName) return diagnostics.filter(d => d.ruleName === ruleName); - return diagnostics; -} diff --git a/__tests__/runtime-test.ts b/__tests__/runtime-test.ts deleted file mode 100644 index f84f076..0000000 --- a/__tests__/runtime-test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import * as api from '../src/pslLint/api'; -import { RuntimeStart } from '../src/pslLint/runtime'; -import * as utils from './ruleUtils'; - -describe('Parameter tests', () => { - - let runtimeDiagnostics: api.Diagnostic[] = []; - - beforeAll(async () => { - runtimeDiagnostics = await utils.getDiagnostics('ZRuntime.PROC', RuntimeStart.name); - }); - - test('Diagnostic count', () => { - expect(runtimeDiagnostics.length).toBe(5); - }); - - test('No diagnostic first start', () => { - expect(utils.diagnosticsOnLine(9, runtimeDiagnostics)).toMatchObject([]); - }); - - test('One diagnostic second start', () => { - const reports = utils.diagnosticsOnLine(13, runtimeDiagnostics); - expect(reports.length).toBe(1); - expect(reports[0].message).toBe(`Declaration "flagged" referenced inside Runtime.start but not in variable list.`); - }); - - test('One diagnostic third start', () => { - const reports = utils.diagnosticsOnLine(18, runtimeDiagnostics); - expect(reports.length).toBe(1); - expect(reports[0].message).toBe(`Declaration "flagged" referenced inside Runtime.start but not in variable list.`); - }); - - test('No diagnostic with comment', () => { - expect(utils.diagnosticsOnLine(24, runtimeDiagnostics)).toMatchObject([]); - }); - - test('No diagnostic fifth start', () => { - expect(utils.diagnosticsOnLine(29, runtimeDiagnostics)).toMatchObject([]); - }); - - test('Method in middle with new variable', () => { - const reports = utils.diagnosticsOnLine(35, runtimeDiagnostics); - expect(reports.length).toBe(1); - expect(reports[0].message).toBe(`Parameter "flaggedParam" referenced inside Runtime.start but not in variable list.`); - }); - - test('Method in middle with new variable', () => { - const reports = utils.diagnosticsOnLine(42, runtimeDiagnostics); - const diagnostic = reports[0] as api.Diagnostic; - const relatedArray = diagnostic.relatedInformation as api.DiagnosticRelatedInformation[]; - const source = relatedArray[0] as api.DiagnosticRelatedInformation; - const reference = relatedArray[1] as api.DiagnosticRelatedInformation; - expect(reports.length).toBe(1); - expect(diagnostic.message).toBe( - `Declaration "notFlaggedTwice" referenced inside Runtime.start but not in variable list.`, - ); - expect(relatedArray.length).toBe(2); - expect(source.message).toBe(`Source of "notFlaggedTwice"`); - expect(reference.message).toBe(`Reference to "notFlaggedTwice"`); - }); - - test('No literal', () => { - const reports = utils.diagnosticsOnLine(49, runtimeDiagnostics); - expect(reports.length).toBe(1); - expect(reports[0].message).toBe(`Declaration "flagged" referenced inside Runtime.start but not in variable list.`); - }); -}); diff --git a/__tests__/tblcolDoc-test.ts b/__tests__/tblcolDoc-test.ts deleted file mode 100644 index 56f7289..0000000 --- a/__tests__/tblcolDoc-test.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as api from '../src/pslLint/api'; -import { TblColDocumentation } from '../src/pslLint/tblcolDoc'; -import * as utils from './ruleUtils'; - -function messageOnLine(lineNumber: number, allDiagnostics: api.Diagnostic[]): string { - const diagnosticsOnLine = utils.diagnosticsOnLine(lineNumber, allDiagnostics); - if (!diagnosticsOnLine.length) return ''; - return diagnosticsOnLine[0].message; -} - -describe('Table and Column Documentation tests', () => { - - let bracesInColDocDiagnostics: api.Diagnostic[] = []; - let withColDocDiagnostics: api.Diagnostic[] = []; - let withoutColDocDiagnostics: api.Diagnostic[] = []; - let withSpaceColDocDiagnostics: api.Diagnostic[] = []; - let bracesInsideColDefDiagnostics: api.Diagnostic[] = []; - let withoutClosedBracesColDiagnostics: api.Diagnostic[] = []; - - let bracesInTblDocDiagnostics: api.Diagnostic[] = []; - let withTblDocDiagnostics: api.Diagnostic[] = []; - let withoutTblDocDiagnostics: api.Diagnostic[] = []; - let withSpaceTblDocDiagnostics: api.Diagnostic[] = []; - let bracesInsideTblDefDiagnostics: api.Diagnostic[] = []; - let withoutClosedBracesTblDiagnostics: api.Diagnostic[] = []; - - beforeAll(async () => { - bracesInColDocDiagnostics = await utils.getDiagnostics('ZTblColDocTst-Col1.COL', TblColDocumentation.name); - withColDocDiagnostics = await utils.getDiagnostics('ZTblColDocTst-Col2.COL', TblColDocumentation.name); - withoutColDocDiagnostics = await utils.getDiagnostics('ZTblColDocTst-Col3.COL', TblColDocumentation.name); - withSpaceColDocDiagnostics = await utils.getDiagnostics('ZTblColDocTst-Col4.COL', TblColDocumentation.name); - bracesInsideColDefDiagnostics = await utils.getDiagnostics('ZTblColDocTst-Col5.COL', TblColDocumentation.name); - withoutClosedBracesColDiagnostics = await utils.getDiagnostics('ZTblColDocTst-Col6.COL', TblColDocumentation.name); - - bracesInTblDocDiagnostics = await utils.getDiagnostics('ZTblColDocTst1.TBL', TblColDocumentation.name); - withTblDocDiagnostics = await utils.getDiagnostics('ZTblColDocTst2.TBL', TblColDocumentation.name); - withoutTblDocDiagnostics = await utils.getDiagnostics('ZTblColDocTst3.TBL', TblColDocumentation.name); - withSpaceTblDocDiagnostics = await utils.getDiagnostics('ZTblColDocTst4.TBL', TblColDocumentation.name); - bracesInsideTblDefDiagnostics = await utils.getDiagnostics('ZTblColDocTst5.TBL', TblColDocumentation.name); - withoutClosedBracesTblDiagnostics = await utils.getDiagnostics('ZTblColDocTst6.TBL', TblColDocumentation.name); - }); - - test('Column documentation', () => { - // Column documentation exists with '{' '}' braces - expect(bracesInColDocDiagnostics.length).toBe(0); - // Column documentation exists - expect(withColDocDiagnostics.length).toBe(0); - // Without } in the column definition.This should be ignored as the compiler should handle it - expect(withoutClosedBracesColDiagnostics.length).toBe(0); - // Without Column documentation and '{' '}' inside the definition - expect(bracesInsideColDefDiagnostics.length).toBe(0); - // Without Column documentation - expect(messageOnLine(36, withoutColDocDiagnostics)) - .toBe(`Documentation missing for data item "ZTblColDocTst-Col3.COL".`); - // Without Column documentation but only space exists after '}' braces - expect(messageOnLine(36, withSpaceColDocDiagnostics)) - .toBe(`Documentation missing for data item "ZTblColDocTst-Col4.COL".`); - }); - - test('Table documentation', () => { - // Table documentation exists with '{' '}' braces - expect(bracesInTblDocDiagnostics.length).toBe(0); - // Table documentation exists - expect(withTblDocDiagnostics.length).toBe(0); - // Without } in the Table definition.This should be ignored as the compiler should handle it - expect(withoutClosedBracesTblDiagnostics.length).toBe(0); - // Without Table documentation and '{' '}' inside the definition - expect(bracesInsideTblDefDiagnostics.length).toBe(0); - // Without Table documentation - expect(messageOnLine(41, withoutTblDocDiagnostics)) - .toBe(`Documentation missing for table definition "ZTblColDocTst3.TBL".`); - // Without Table documentation but only space exists after '}' braces - expect(messageOnLine(41, withSpaceTblDocDiagnostics)) - .toBe(`Documentation missing for table definition "ZTblColDocTst4.TBL".`); - }); -}); diff --git a/icons/dark/arrow-down.svg b/icons/dark/arrow-down.svg deleted file mode 100644 index c31d63a..0000000 --- a/icons/dark/arrow-down.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - image/svg+xml - - arrow-down - - - - - - arrow-down - Created with Sketch. - - - - - - - diff --git a/icons/dark/arrow-up.svg b/icons/dark/arrow-up.svg deleted file mode 100644 index 41883fc..0000000 --- a/icons/dark/arrow-up.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - image/svg+xml - - arrow-up - - - - - - arrow-up - Created with Sketch. - - - - - - - diff --git a/icons/dark/gear.svg b/icons/dark/gear.svg deleted file mode 100644 index 9aa01de..0000000 --- a/icons/dark/gear.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - image/svg+xml - - gear - - - - - - gear - Created with Sketch. - - - - - - - diff --git a/icons/dark/link.svg b/icons/dark/link.svg deleted file mode 100644 index 1b44743..0000000 --- a/icons/dark/link.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - image/svg+xml - - link - - - - - - link - Created with Sketch. - - - - - - - diff --git a/icons/dark/sync.svg b/icons/dark/sync.svg deleted file mode 100644 index 7859522..0000000 --- a/icons/dark/sync.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - image/svg+xml - - sync - - - - - - sync - Created with Sketch. - - - - - - - diff --git a/icons/dark/triangle-right.svg b/icons/dark/triangle-right.svg deleted file mode 100644 index 44b0855..0000000 --- a/icons/dark/triangle-right.svg +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - image/svg+xml - - triangle-right - - - - - - triangle-right - Created with Sketch. - - - - - - - diff --git a/icons/light/arrow-down.svg b/icons/light/arrow-down.svg deleted file mode 100644 index 0b2bcd5..0000000 --- a/icons/light/arrow-down.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - arrow-down - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/icons/light/arrow-up.svg b/icons/light/arrow-up.svg deleted file mode 100644 index f6cb23a..0000000 --- a/icons/light/arrow-up.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - arrow-up - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/icons/light/gear.svg b/icons/light/gear.svg deleted file mode 100644 index e72ca6a..0000000 --- a/icons/light/gear.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - gear - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/icons/light/link.svg b/icons/light/link.svg deleted file mode 100644 index 39e4933..0000000 --- a/icons/light/link.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - link - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/icons/light/sync.svg b/icons/light/sync.svg deleted file mode 100644 index d57fe3c..0000000 --- a/icons/light/sync.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - sync - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/icons/light/triangle-right.svg b/icons/light/triangle-right.svg deleted file mode 100644 index 3867ddf..0000000 --- a/icons/light/triangle-right.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - image/svg+xml - - - - - - - triangle-right - Created with Sketch. - - - - - - - diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..7363816 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,12 @@ +module.exports = { + moduleFileExtensions: [ + "ts", + "js", + ], + transform: { + "^.+\\.tsx?$": "ts-jest" + }, + testMatch: [ + "**/test/**/*.test.(ts|js)" + ], +}; \ No newline at end of file diff --git a/languages/def-language-configuration.json b/languages/def-language-configuration.json deleted file mode 100644 index 53ccbd2..0000000 --- a/languages/def-language-configuration.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "comments": { - "lineComment": "//", - "blockComment": [ "/*", "*/" ] - }, - "brackets": [ - ["{", "}"], - ["[", "]"] - ], - "autoClosingPairs": [ - { "open": "{", "close": "}", "notIn": ["string"] }, - { "open": "[", "close": "]", "notIn": ["string"] }, - { "open": "(", "close": ")", "notIn": ["string"] }, - { "open": "'", "close": "'", "notIn": ["string"] }, - { "open": "\"", "close": "\"", "notIn": ["string", "comment"] }, - { "open": "`", "close": "`", "notIn": ["string", "comment"] } - ] -} \ No newline at end of file diff --git a/languages/psl-language-configuration.json b/languages/psl-language-configuration.json deleted file mode 100644 index 568db99..0000000 --- a/languages/psl-language-configuration.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "comments": { - // symbol used for single line comment. Remove this entry if your language does not support line comments - "lineComment": "//", - // symbols used for start and end a block comment. Remove this entry if your language does not support block comments - "blockComment": [ "/*", "*/" ] - }, - // symbols used as brackets - "brackets": [ - ["{", "}"], - ["(", ")"] - ], - // symbols that are auto closed when typing - "autoClosingPairs": [ - ["{", "}"], - ["(", ")"], - ["\"", "\""] - ], - // symbols that that can be used to surround a selection - "surroundingPairs": [ - ["{", "}"], - ["(", ")"], - ["\"", "\""] - ] -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 21ad980..e130876 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,33 +1,25 @@ { - "name": "vscode-psl", - "version": "1.13.2", + "name": "psl-parser", + "version": "0.0.3", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "vscode-psl", - "version": "1.13.2", + "name": "psl-parser", + "version": "0.0.3", "license": "MIT", "dependencies": { - "fs-extra": "^10.1.0", - "jsonc-parser": "^3.2.0", - "minimatch": "^5.1.0", - "request-light": "^0.5.8", - "vscode-json-languageservice": "^5.1.1" + "fs-extra": "^10.1.0" }, "devDependencies": { "@types/fs-extra": "^9.0.13", "@types/jest": "^29.2.0", - "@types/minimatch": "^5.1.2", "@types/node": "^18.11.4", - "@types/vscode": "^1.72.0", "jest": "^29.2.1", + "jsonc-parser": "^3.2.0", "ts-jest": "^29.0.3", "tslint": "^5.20.1", "typescript": "^4.8.4" - }, - "engines": { - "vscode": "^1.72.2" } }, "node_modules/@ampproject/remapping": { @@ -1418,12 +1410,6 @@ "pretty-format": "^29.0.0" } }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, "node_modules/@types/node": { "version": "18.11.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.4.tgz", @@ -1442,12 +1428,6 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, - "node_modules/@types/vscode": { - "version": "1.72.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.72.0.tgz", - "integrity": "sha512-WvHluhUo+lQvE3I4wUagRpnkHuysB4qSyOQUyIAS9n9PYMJjepzTUD8Jyks0YeXoPD0UGctjqp2u84/b3v6Ydw==", - "dev": true - }, "node_modules/@types/yargs": { "version": "17.0.13", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", @@ -1685,15 +1665,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/braces": { "version": "3.0.2", @@ -2130,20 +2103,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -4118,7 +4077,8 @@ "node_modules/jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true }, "node_modules/jsonfile": { "version": "6.1.0", @@ -4252,17 +4212,6 @@ "node": ">=6" } }, - "node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/minimist": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", @@ -4533,11 +4482,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "node_modules/request-light": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.5.8.tgz", - "integrity": "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==" - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -5057,38 +5001,6 @@ "node": ">=10.12.0" } }, - "node_modules/vscode-json-languageservice": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-5.1.1.tgz", - "integrity": "sha512-EtAcTD6MOfyf8+MokDsAHNM7ttuZvCo077w9aMtJiyps41gkOcoBThAbXDk6Y0Oi6ki5aDs8lgY4KxYiVW/lxA==", - "dependencies": { - "jsonc-parser": "^3.2.0", - "vscode-languageserver-textdocument": "^1.0.7", - "vscode-languageserver-types": "^3.17.2", - "vscode-nls": "^5.2.0", - "vscode-uri": "^3.0.6" - } - }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz", - "integrity": "sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg==" - }, - "node_modules/vscode-languageserver-types": { - "version": "3.17.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz", - "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==" - }, - "node_modules/vscode-nls": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", - "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==" - }, - "node_modules/vscode-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz", - "integrity": "sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ==" - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -6311,12 +6223,6 @@ "pretty-format": "^29.0.0" } }, - "@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, "@types/node": { "version": "18.11.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.4.tgz", @@ -6335,12 +6241,6 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, - "@types/vscode": { - "version": "1.72.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.72.0.tgz", - "integrity": "sha512-WvHluhUo+lQvE3I4wUagRpnkHuysB4qSyOQUyIAS9n9PYMJjepzTUD8Jyks0YeXoPD0UGctjqp2u84/b3v6Ydw==", - "dev": true - }, "@types/yargs": { "version": "17.0.13", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", @@ -6523,15 +6423,8 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "requires": { - "balanced-match": "^1.0.0" - } + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "braces": { "version": "3.0.2", @@ -6859,13 +6752,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -8332,7 +8218,8 @@ "jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true }, "jsonfile": { "version": "6.1.0", @@ -8439,14 +8326,6 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, - "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "requires": { - "brace-expansion": "^2.0.1" - } - }, "minimist": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", @@ -8646,11 +8525,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "request-light": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.5.8.tgz", - "integrity": "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==" - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -9011,38 +8885,6 @@ "convert-source-map": "^1.6.0" } }, - "vscode-json-languageservice": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-5.1.1.tgz", - "integrity": "sha512-EtAcTD6MOfyf8+MokDsAHNM7ttuZvCo077w9aMtJiyps41gkOcoBThAbXDk6Y0Oi6ki5aDs8lgY4KxYiVW/lxA==", - "requires": { - "jsonc-parser": "^3.2.0", - "vscode-languageserver-textdocument": "^1.0.7", - "vscode-languageserver-types": "^3.17.2", - "vscode-nls": "^5.2.0", - "vscode-uri": "^3.0.6" - } - }, - "vscode-languageserver-textdocument": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz", - "integrity": "sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg==" - }, - "vscode-languageserver-types": { - "version": "3.17.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz", - "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==" - }, - "vscode-nls": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", - "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==" - }, - "vscode-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz", - "integrity": "sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ==" - }, "walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", diff --git a/package.json b/package.json index edc9ea3..9aba00b 100644 --- a/package.json +++ b/package.json @@ -1,875 +1,44 @@ { - "name": "vscode-psl", - "displayName": "vscode-psl", - "description": "Profile Scripting Language support", - "version": "1.13.2", - "preview": true, - "publisher": "ing-bank", - "engines": { - "vscode": "^1.72.2" - }, - "categories": [ - "Programming Languages" + "name": "psl-parser", + "version": "0.0.3", + "description": "Profile Scripting Language Parser", + "keywords": [ + "PSL", + "parser", + "profile", + "scripting", + "language" ], + "homepage": "https://github.com/ing-bank/vscode-psl#readme", + "bugs": { + "url": "https://github.com/ing-bank/vscode-psl/issues" + }, "license": "MIT", - "activationEvents": [ - "workspaceContains:dataqwik", - "workspaceContains:.vscode/environment.json", - "onLanguage:psl", - "onCommand:psl.getElement", - "onCommand:psl.refreshElement", - "onCommand:psl.getTable", - "onCommand:psl.testCompile", - "onCommand:psl.configureEnvironment", - "onCommand:psl.sendElement", - "onCommand:psl.compileAndLink", - "onCommand:psl.runPSL", - "onCommand:psl.launchHostTerminal" + "author": "atiplea", + "contributors": [ + "SOliveira" ], - "main": "./out/src/extension", - "contributes": { - "languages": [ - { - "id": "profileTable", - "aliases": [ - "Profile Table Definition" - ], - "extensions": [ - ".TBL" - ], - "configuration": "./def-language-configuration.json" - }, - { - "id": "profileColumn", - "aliases": [ - "Profile Column Definition" - ], - "extensions": [ - ".COL" - ], - "configuration": "./languages/def-language-configuration.json" - }, - { - "id": "profileData", - "aliases": [ - "Profile Data Item" - ], - "extensions": [ - ".DAT" - ] - }, - { - "id": "profileSerialData", - "aliases": [ - "Profile Serialized Data Element" - ], - "extensions": [ - ".serial" - ] - }, - { - "id": "psl", - "aliases": [ - "Profile Scripting Language", - "psl" - ], - "extensions": [ - ".PROC", - ".PSL", - ".psl" - ], - "configuration": "./languages/psl-language-configuration.json" - }, - { - "id": "profileBatch", - "aliases": [ - "Profile Batch Definition" - ], - "extensions": [ - ".BATCH" - ], - "configuration": "./languages/psl-language-configuration.json" - }, - { - "id": "profileTrigger", - "aliases": [ - "Profile Trigger Definition" - ], - "extensions": [ - ".TRIG" - ], - "configuration": "./languages/psl-language-configuration.json" - } - ], - "grammars": [ - { - "language": "psl", - "scopeName": "source.psl", - "path": "./syntaxes/psl.tmLanguage.json" - }, - { - "language": "profileBatch", - "scopeName": "source.psl", - "path": "./syntaxes/psl.tmLanguage.json" - }, - { - "language": "profileTrigger", - "scopeName": "source.psl", - "path": "./syntaxes/psl.tmLanguage.json" - }, - { - "language": "profileTable", - "scopeName": "source.json", - "path": "./syntaxes/JSON.tmLanguage" - }, - { - "language": "profileColumn", - "scopeName": "source.json", - "path": "./syntaxes/JSON.tmLanguage" - } - ], - "jsonValidation": [ - { - "fileMatch": "environment.json", - "url": "./schemas/environmentSchema.json" - }, - { - "fileMatch": "environments.json", - "url": "./schemas/environmentsSchema.json" - } - ], - "snippets": [ - { - "language": "psl", - "path": "./snippets/psl.json" - }, - { - "language": "profileTable", - "path": "./snippets/tableDefinition.json" - }, - { - "language": "profileColumn", - "path": "./snippets/columnDefinition.json" - } - ], - "configurationDefaults": { - "[psl]": { - "editor.snippetSuggestions": "bottom", - "editor.insertSpaces": false, - "editor.wordSeparators": "`~!@^&*()-=+[{]}\\|;:'\",.<>/?_$" - }, - "[profileBatch]": { - "editor.snippetSuggestions": "bottom", - "editor.insertSpaces": false, - "editor.wordSeparators": "`~!@^&*()-=+[{]}\\|;:'\",.<>/?_$" - }, - "[profileTrigger]": { - "editor.snippetSuggestions": "bottom", - "editor.insertSpaces": false, - "editor.wordSeparators": "`~!@^&*()-=+[{]}\\|;:'\",.<>/?_$" - }, - "[profileColumn]": { - "editor.insertSpaces": false - }, - "[profileData]": { - "editor.insertSpaces": false, - "editor.renderWhitespace": "boundary", - "diffEditor.ignoreTrimWhitespace": false - }, - "[profileSerialData]": { - "editor.insertSpaces": false, - "editor.renderWhitespace": "boundary", - "diffEditor.ignoreTrimWhitespace": false - }, - "[profileTable]": { - "editor.insertSpaces": false - } - }, - "commands": [ - { - "command": "psl.setGtmDebug", - "title": "Set GT.M Debug", - "category": "PSL" - }, - { - "command": "psl.stepOut", - "title": "Terminal Step Out", - "category": "PSL" - }, - { - "command": "psl.stepIn", - "title": "Terminal Step In", - "category": "PSL" - }, - { - "command": "psl.stepOver", - "title": "Terminal Step Over", - "category": "PSL" - }, - { - "command": "psl.getElement", - "title": "Get Element from Host", - "category": "PSL" - }, - { - "command": "psl.refreshElement", - "title": "Refresh from Host", - "category": "PSL", - "icon": { - "dark": "icons/dark/sync.svg", - "light": "icons/light/sync.svg" - } - }, - { - "command": "psl.getTable", - "title": "Table Get from Host", - "category": "PSL" - }, - { - "command": "psl.testCompile", - "title": "Test Compile", - "category": "PSL", - "icon": { - "dark": "icons/dark/gear.svg", - "light": "icons/light/gear.svg" - } - }, - { - "command": "psl.configureEnvironment", - "title": "Configure Environment", - "category": "PSL" - }, - { - "command": "psl.sendElement", - "title": "Send to Host", - "category": "PSL", - "icon": { - "dark": "icons/dark/arrow-up.svg", - "light": "icons/light/arrow-up.svg" - } - }, - { - "command": "psl.compileAndLink", - "title": "Compile and Link", - "category": "PSL", - "icon": { - "dark": "icons/dark/link.svg", - "light": "icons/light/link.svg" - } - }, - { - "command": "psl.runPSL", - "title": "Run PSL", - "category": "PSL", - "icon": { - "dark": "icons/dark/triangle-right.svg", - "light": "icons/light/triangle-right.svg" - } - }, - { - "command": "psl.runTest", - "title": "Run Test", - "category": "PSL" - }, - { - "command": "psl.runCoverage", - "title": "Run Test (with Coverage)", - "category": "PSL" - }, - { - "command": "psl.sendTable", - "title": "Table Send to Host", - "category": "PSL" - }, - { - "command": "psl.refreshTable", - "title": "Table Refresh from Host", - "category": "PSL" - }, - { - "command": "psl.previewDocumentation", - "title": "Preview Documentation", - "category": "PSL" - } - ], - "menus": { - "explorer/context": [ - { - "when": "explorerResourceIsFolder", - "command": "psl.getElement", - "group": "PSL.3" - }, - { - "when": "explorerResourceIsFolder", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "explorerResourceIsFolder", - "command": "psl.getTable", - "group": "PSL.3" - }, - { - "when": "explorerResourceIsFolder", - "command": "psl.testCompile", - "group": "PSL.2" - }, - { - "when": "explorerResourceIsFolder", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "explorerResourceIsFolder", - "command": "psl.runPSL", - "group": "PSL.2" - }, - { - "when": "explorerResourceIsFolder", - "command": "psl.compileAndLink", - "group": "PSL.2" - }, - { - "when": "resourceLangId == psl && !explorerResourceIsFolder", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileData && !explorerResourceIsFolder", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileSerialData && !explorerResourceIsFolder", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTable && !explorerResourceIsFolder", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileColumn && !explorerResourceIsFolder", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileBatch && !explorerResourceIsFolder", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTrigger && !explorerResourceIsFolder", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == psl && !explorerResourceIsFolder", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileData && !explorerResourceIsFolder", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileSerialData && !explorerResourceIsFolder", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTable && !explorerResourceIsFolder", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileColumn && !explorerResourceIsFolder", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileBatch && !explorerResourceIsFolder", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTrigger && !explorerResourceIsFolder", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == psl && !explorerResourceIsFolder", - "command": "psl.runPSL", - "group": "PSL.2" - }, - { - "when": "resourceLangId == psl && !explorerResourceIsFolder", - "command": "psl.compileAndLink", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTable && !explorerResourceIsFolder", - "command": "psl.compileAndLink", - "group": "PSL.2" - }, - { - "when": "resourceLangId == psl && !explorerResourceIsFolder", - "command": "psl.testCompile", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTable && !explorerResourceIsFolder", - "command": "psl.sendTable", - "group": "PSL.1" - }, - { - "when": "resourceLangId == profileColumn && !explorerResourceIsFolder", - "command": "psl.sendTable", - "group": "PSL.1" - }, - { - "when": "resourceLangId == profileTable && !explorerResourceIsFolder", - "command": "psl.refreshTable", - "group": "PSL.1" - }, - { - "when": "resourceLangId == profileColumn && !explorerResourceIsFolder", - "command": "psl.refreshTable", - "group": "PSL.1" - }, - { - "command": "psl.configureEnvironment", - "group": "PSL.4" - } - ], - "editor/context": [ - { - "when": "resourceLangId == psl", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileData", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileSerialData", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTable", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileColumn", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileBatch", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTrigger", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "psl.isProfileElement", - "command": "psl.refreshElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == psl", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileData", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileSerialData", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTable", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileColumn", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileBatch", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTrigger", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "when": "psl.isProfileElement", - "command": "psl.sendElement", - "group": "PSL.2" - }, - { - "command": "psl.getElement", - "group": "PSL.4" - }, - { - "command": "psl.getTable", - "group": "PSL.4" - }, - { - "when": "resourceLangId == psl", - "command": "psl.testCompile", - "group": "PSL.2" - }, - { - "when": "resourceLangId == psl", - "command": "psl.runPSL", - "group": "PSL.2" - }, - { - "when": "resourceFilename =~ /^(Ut|St)/ && resourceLangId == psl && psl.runTestContext", - "command": "psl.runTest", - "group": "PSL.3" - }, - { - "when": "resourceFilename =~ /^(Ut|St)/ && resourceLangId == psl && psl.runCoverageContext", - "command": "psl.runCoverage", - "group": "PSL.3" - }, - { - "when": "resourceLangId == psl", - "command": "psl.compileAndLink", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTable", - "command": "psl.compileAndLink", - "group": "PSL.2" - }, - { - "when": "resourceLangId == profileTable", - "command": "psl.sendTable", - "group": "PSL.1" - }, - { - "when": "resourceLangId == profileColumn", - "command": "psl.sendTable", - "group": "PSL.1" - }, - { - "when": "resourceLangId == profileTable", - "command": "psl.refreshTable", - "group": "PSL.1" - }, - { - "when": "resourceLangId == profileColumn", - "command": "psl.refreshTable", - "group": "PSL.1" - } - ], - "editor/title": [ - { - "command": "psl.previewDocumentation", - "group": "navigation@-206", - "when": "resourceLangId == psl && psl.hasDocumentationServer" - }, - { - "command": "psl.refreshElement", - "group": "navigation@-205", - "when": "resourceLangId == profileData" - }, - { - "command": "psl.refreshElement", - "group": "navigation@-205", - "when": "resourceLangId == profileSerialData" - }, - { - "command": "psl.refreshElement", - "group": "navigation@-205", - "when": "resourceLangId == profileBatch" - }, - { - "command": "psl.refreshElement", - "group": "navigation@-205", - "when": "resourceLangId == profileTrigger" - }, - { - "command": "psl.refreshElement", - "group": "navigation@-205", - "when": "resourceLangId == psl" - }, - { - "command": "psl.refreshElement", - "group": "navigation@-205", - "when": "psl.isProfileElement" - }, - { - "command": "psl.refreshElement", - "group": "navigation@-205", - "when": "resourceLangId == profileTable" - }, - { - "command": "psl.refreshElement", - "group": "navigation@-205", - "when": "resourceLangId == profileColumn" - }, - { - "command": "psl.testCompile", - "group": "navigation@-204", - "when": "resourceLangId == psl" - }, - { - "command": "psl.sendElement", - "group": "navigation@-203", - "when": "resourceLangId == profileBatch" - }, - { - "command": "psl.sendElement", - "group": "navigation@-203", - "when": "resourceLangId == profileTrigger" - }, - { - "command": "psl.sendElement", - "group": "navigation@-203", - "when": "resourceLangId == profileData" - }, - { - "command": "psl.sendElement", - "group": "navigation@-203", - "when": "resourceLangId == profileSerialData" - }, - { - "command": "psl.sendElement", - "group": "navigation@-203", - "when": "resourceLangId == psl" - }, - { - "command": "psl.sendElement", - "group": "navigation@-203", - "when": "psl.isProfileElement" - }, - { - "command": "psl.sendElement", - "group": "navigation@-203", - "when": "resourceLangId == profileTable" - }, - { - "command": "psl.sendElement", - "group": "navigation@-203", - "when": "resourceLangId == profileColumn" - }, - { - "command": "psl.compileAndLink", - "group": "navigation@-202", - "when": "resourceLangId == psl" - }, - { - "command": "psl.compileAndLink", - "group": "navigation@-202", - "when": "resourceLangId == profileTable" - }, - { - "command": "psl.runPSL", - "group": "navigation@-201", - "when": "resourceLangId == psl" - } - ], - "commandPalette": [ - { - "when": "resourceLangId == profileTable", - "command": "psl.sendTable", - "group": "PSL" - }, - { - "when": "resourceLangId == profileColumn", - "command": "psl.sendTable", - "group": "PSL" - }, - { - "when": "resourceLangId == profileTable", - "command": "psl.refreshTable", - "group": "PSL" - }, - { - "when": "resourceLangId == psl && psl.hasDocumentationServer", - "command": "psl.previewDocumentation", - "group": "PSL" - }, - { - "when": "resourceLangId == profileColumn", - "command": "psl.refreshTable", - "group": "PSL" - } - ] - }, - "keybindings": [ - { - "when": "resourceLangId == psl", - "command": "psl.testCompile", - "key": "Ctrl+Shift+B" - }, - { - "key": "Ctrl+E", - "command": "psl.stepOut", - "when": "terminalFocus && psl.gtmDebug" - }, - { - "key": "Ctrl+Q", - "command": "psl.stepIn", - "when": "terminalFocus && psl.gtmDebug" - }, - { - "key": "Ctrl+W", - "command": "psl.stepOver", - "when": "terminalFocus && psl.gtmDebug" - }, - { - "command": "psl.launchHostTerminal", - "key": "win+oem_3" - } - ], - "configuration": { - "type": "object", - "title": "PSL Configuration", - "properties": { - "psl.lint": { - "scope": "resource", - "type": "string", - "default": "config", - "enum": [ - "config", - "all", - "none" - ], - "description": "Whether to lint files written in PSL." - }, - "psl.previewFeatures": { - "scope": "resource", - "type": "boolean", - "default": false, - "description": "Set true to enable the latest developing features." - }, - "psl.gtmDebugEnabled": { - "scope": "machine", - "type": "boolean", - "default": false, - "description": "Set true to keep GT.M Debug on by default." - }, - "psl.customTasks": { - "scope": "resource", - "type": "array", - "items": { - "type": "object", - "required": [ - "command", - "mrpcID", - "request" - ], - "properties": { - "command": { - "type": "string", - "enum": [ - "runTest", - "runCoverage" - ], - "enumDescriptions": [ - "A command for running tests via PslUtTestCase.", - "A command for running tests with coverage output." - ] - }, - "mrpcID": { - "type": "string", - "description": "The MRPC ID supplied in the client message. For example \"121\" or \"^ZMRPC121\"." - }, - "request": { - "type": "string", - "description": "The request type. For example \"PSLRUNTEST\"." - } - } - } - }, - "psl.documentationServer": { - "scope": "resource", - "type": "string", - "description": "HTTP POST endpoint that responds with PSL documentation in markdown format." - }, - "psl.trailingNewline": { - "scope": "resource", - "type": "string", - "enum": [ - "default", - "always", - "never" - ], - "enumDescriptions": [ - "Allows the default behavior, makes no modification.", - "Always add a trailing newline if not present.", - "Remove trailing newlines if they are present." - ], - "default": "default", - "description": "Adds a trailing newline after a \"Get\" or \"Refresh\"." - } - } - } + "main": "out/index.js", + "repository": { + "type": "git", + "url": "https://github.com/ing-bank/vscode-psl.git" }, "scripts": { "compile": "tsc -p ./", - "compile-lint": "tsc -p ./src/pslLint/cli", - "compile-parser": "tsc -p ./src/parser", - "lint": "tslint -c tslint.json --project .", "watch": "npm run compile -- -watch", "test": "jest" }, - "repository": { - "type": "git", - "url": "https://github.com/ing-bank/vscode-psl" + "dependencies": { + "fs-extra": "^10.1.0" }, "devDependencies": { "@types/fs-extra": "^9.0.13", "@types/jest": "^29.2.0", - "@types/minimatch": "^5.1.2", "@types/node": "^18.11.4", - "@types/vscode": "^1.72.0", "jest": "^29.2.1", "ts-jest": "^29.0.3", "tslint": "^5.20.1", - "typescript": "^4.8.4" - }, - "dependencies": { - "fs-extra": "^10.1.0", - "jsonc-parser": "^3.2.0", - "minimatch": "^5.1.0", - "request-light": "^0.5.8", - "vscode-json-languageservice": "^5.1.1" - }, - "jest": { - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testRegex": ".*?/__tests__/.*-test(\\.ts|\\.js)", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ] + "typescript": "^4.8.4", + "jsonc-parser": "^3.2.0" } } diff --git a/schemas/environmentSchema.json b/schemas/environmentSchema.json deleted file mode 100644 index e26ddf4..0000000 --- a/schemas/environmentSchema.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "required": ["names"], - "default": { - "names": [] - }, - "properties": { - "names": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The names of your selected environments." - } - } -} \ No newline at end of file diff --git a/schemas/environmentsSchema.json b/schemas/environmentsSchema.json deleted file mode 100644 index c2cb1c7..0000000 --- a/schemas/environmentsSchema.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "required": ["environments"], - "properties": { - "environments": { - "type": "array", - "description": "A list of all available environments.", - "items": { - "default": { - "name": "", - "host": "", - "port": 0, - "user": "", - "password": "", - "sshLogin": "", - "serverType": "SCA$IBS", - "encoding": "utf8" - }, - "properties": { - "name": { - "type": "string", - "description": "A name you can use to identifiy this specific configuration." - }, - "host": { - "type": "string", - "description": "The host/server name." - }, - "port": { - "type": "integer", - "description": "The MTM port number of your environment." - }, - "user": { - "type": "string", - "description": "User to log in to the driver." - }, - "password": { - "type": "string", - "description": "The user's password." - }, - "sshLogin": { - "type": "string", - "description": "The login used to ssh into the Profile Server." - }, - "serverType": { - "type": "string", - "description": "The server type. Default value is \"SCA$IBS\"." - }, - "encoding": { - "type": "string", - "description": "Encoding to use in request/response. The default value is \"utf8\".", - "enum": ["ascii", "utf8", "ucs2", "base64", "latin1", "binary", "hex"] - } - } - } - } - }, - "default": { - "environments": [ - {"name": "" , "host": "" , "port": 0, "user": "" , "password": "" , "sshLogin": "" } - - ] - } -} - diff --git a/snippets/columnDefinition.json b/snippets/columnDefinition.json deleted file mode 100644 index 700465a..0000000 --- a/snippets/columnDefinition.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "Column Definition": { - "prefix": "columndefinition", - "body": [ - "{", - "\t\"%LIBS\" : \"SYSDEV\",", - "\t\"FID\" : \"${1:tableName}\",", - "\t\"DI\" : \"${2:columnName}\",", - "\t\"ALIAS\" : \"${3:alias}\",", - "\t\"CMP\" : ${4:computed},", - "\t\"DES\" : ${5:description},", - "\t\"LEN\" : ${6:lengthInteger},", - "\t\"MDD\" : null,", - "\t\"MIN\" : null,", - "\t\"NOD\" : \"${7:nodeIdentifier}\",", - "\t\"POS\" : ${8:positionInteger},", - "\t\"REQ\" : ${9:required},", - "\t\"RHD\" : \"${10:reportHeader}\",", - "\t\"TYP\" : \"${11:dataType}\",", - "}", - "${12:Column documentation (do not exceed 80-character margin)}" - ], - "description": "Column Definition" - } -} diff --git a/snippets/psl.json b/snippets/psl.json deleted file mode 100644 index fd92381..0000000 --- a/snippets/psl.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "Documentation": { - "prefix": "documentation", - "body": [ - "/* DOC ----------------------------------------------------------------", - "$0", - "** ENDDOC */" - ], - "description": "Adds a documentation comment block" - }, - "Separator": { - "prefix": "separator", - "body": [ - "// --------------------------------------------------------------------" - ], - "description": "Adds a comment separator" - }, - "For Loop (with index)": { - "prefix": "forIndex", - "body": [ - "type Number ${1:}", - "for ${1:}=${2:}:${3:}:${4:} {", - "\t$0", - "}" - ] - }, - "For Loop (order)": { - "prefix": "forOrder", - "body": [ - "type String ${1:} = \"\"", - "for set ${1:} = ${2:}(${1:}).order() quit:${1:}.isNull() {", - "\t$0", - "}" - ] - }, - "Accept Directive":{ - "prefix": "#ACCEPT", - "body": [ - "#ACCEPT GROUP=${1:}; DATE=${2:}; PGM=${3:}; CR=${4:}" - ], - "description": "Suppresses warnings generated by the next line of PSL source code." - }, - "Revision History":{ - "prefix": "revisionHistory", - "body": [ - "/* Revision History ----------------------------------------------------", - "${1:$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE}, ${2:}, ${3:}", - "\t* $0", - "*/" - ], - "description": "Adds a revision history comment block." - }, - "Method":{ - "prefix": "method", - "body": [ - "\t// --------------------------------------------------------------------", - "${1:private} ${2:void} ${3:}()", - "\t/* DOC ----------------------------------------------------------------", - "\t$0", - "\t** ENDDOC */" - ], - "description": "Adds a method stub with a documentation comment block." - }, - "Property": { - "prefix": "pslProperty", - "body": [ - "// --------------------------------------------------------------------", - "#PROPERTYDEF $1 class = $2", - "/* DOC ----------------------------------------------------------------", - "$0", - "** ENDDOC */" - ] - }, - "pslmain":{ - "prefix": "psip", - "body": [ - "\t// --------------------------------------------------------------------", - "public static Integer pslmain(void args(String))", - "\t/* DOC ----------------------------------------------------------------", - "\tCommand line entry point.", - "", - "\t@param\targs\tCommand line arguments", - "\t** ENDDOC */", - "\t$0", - "\treturn 0" - ], - "description": "Add the method signature for a pslmain method." - } -} diff --git a/snippets/tableDefinition.json b/snippets/tableDefinition.json deleted file mode 100644 index a6b685d..0000000 --- a/snippets/tableDefinition.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "Table Definition": { - "prefix": "tabledefinition", - "body": [ - "{", - "\t\"%LIBS\" : \"SYSDEV\",", - "\t\"FID\" : \"${1:tableName}\",", - "\t\"ACCKEYS\" : \"${2:keys}\",", - "\t\"ALIAS\" : null,", - "\t\"CACHED\" : null,", - "\t\"DEL\" : ${3:delimiterInteger},", - "\t\"DES\" : \"${4:description}\",", - "\t\"FILETYP\" : ${5:fileTypeInteger},", - "\t\"FSN\" : \"f${1:tableName}\",", - "\t\"GLOBAL\" : \"${1:tableName}\",", - "\t\"GLREF\" : \"^${1:tableName}(${2:keys}\",", - "\t\"PSLPACKAGE\" : \"${6:packageName}\",", - "\t\"PSLRESTRICTION\" : null,", - "\t\"RECTYP\" : 1,", - "\t\"SYSSN\" : \"PBS\"", - "}", - "${7:// Table documentation (do not exceed 80 character margin)}" - ], - "description": "Table Definition" - } -} \ No newline at end of file diff --git a/src/common/context.ts b/src/common/context.ts deleted file mode 100644 index 12276ff..0000000 --- a/src/common/context.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as vscode from 'vscode'; -import * as fsExtra from 'fs-extra'; - -export const enum ContextMode { - FILE = 1, - DIRECTORY = 2, - EMPTY = 3 -} - -export interface ExtensionCommandContext { - fsPath: string; -} - -export interface HostCommandContext { - fsPath: string; - mode: ContextMode; -} - -export function getFullContext(context: ExtensionCommandContext | undefined, useActiveTextEditor?: boolean): HostCommandContext { - let fsPath: string = ''; - let mode: ContextMode; - let activeTextEditor = vscode.window.activeTextEditor; - - if (context) { - fsPath = context.fsPath; - mode = fsExtra.lstatSync(fsPath).isFile() ? ContextMode.FILE : ContextMode.DIRECTORY; - return {fsPath, mode}; - } - else if (useActiveTextEditor && activeTextEditor) { - fsPath = activeTextEditor.document.fileName; - mode = ContextMode.FILE; - return {fsPath, mode}; - } - else { - mode = ContextMode.EMPTY; - return {fsPath, mode}; - } -} \ No newline at end of file diff --git a/src/common/diagnostics.ts b/src/common/diagnostics.ts deleted file mode 100644 index 94d98c7..0000000 --- a/src/common/diagnostics.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as vscode from 'vscode'; - -export class PSLDiagnostic { - - static diagnosticCollections: vscode.DiagnosticCollection[] = []; - - static setDiagnostics(pslDiagnostics: PSLDiagnostic[], envName: string, fsPath: string) { - let diagnosticMap: Map = new Map(); - pslDiagnostics.forEach(pslDiagnostic => { - let canonicalFile = vscode.Uri.file(pslDiagnostic.file).toString(); - let diagnostics = diagnosticMap.get(canonicalFile); - pslDiagnostic.diagnostic.source = envName; - if (!diagnostics) { diagnostics = []; } - - diagnostics.push(pslDiagnostic.diagnostic); - diagnosticMap.set(canonicalFile, diagnostics); - }); - let collection = this.diagnosticCollections.find(col => col.name === envName); - if (!collection) { - collection = this.registerCollection(envName); - } - let uri = vscode.Uri.file(fsPath); - collection.delete(uri); - diagnosticMap.forEach((diags, file) => { - collection.set(vscode.Uri.parse(file), diags); - - }); - } - - static registerCollection(envName: string): vscode.DiagnosticCollection { - let collection = vscode.languages.createDiagnosticCollection(envName); - vscode.workspace.onDidCloseTextDocument((textDocument) => { - let uri = textDocument.uri; - collection.delete(uri); - }) - this.diagnosticCollections.push(collection); - return collection; - } - - message: string; - severity: vscode.DiagnosticSeverity; - file: string; - range: vscode.Range; - - diagnostic: vscode.Diagnostic; - - constructor(message: string, severity: vscode.DiagnosticSeverity, file: string, range: vscode.Range) { - this.message = message; - this.severity = severity; - this.file = file; - this.range = range; - - this.diagnostic = new vscode.Diagnostic(this.range, this.message, this.severity); - } -} diff --git a/src/common/environment.ts b/src/common/environment.ts deleted file mode 100644 index 0f0bd3d..0000000 --- a/src/common/environment.ts +++ /dev/null @@ -1,347 +0,0 @@ -import * as vscode from 'vscode'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import * as jsonc from 'jsonc-parser'; -import * as os from 'os'; - -const configEnvCommand = 'psl.configureEnvironment'; - -const LOCAL_ENV_DIR = path.join('.vscode', 'environment.json'); - -const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 900); -statusBar.command = configEnvCommand; - -export function activate(context: vscode.ExtensionContext) { - - context.subscriptions.push( - vscode.commands.registerCommand( - configEnvCommand, configureEnvironmentHandler - ) - ); - - context.subscriptions.push(statusBar); - - context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor((e) => changeTextEditorHandler(e))); - changeTextEditorHandler(vscode.window.activeTextEditor) - -} - -export interface EnvironmentConfig { - name: string; - host: string; - port: number; - user: string; - password: string; - sshLogin?: string; - serverType?: string; - encoding?: BufferEncoding; -} - -interface GlobalConfig { - environments: EnvironmentConfig[] -} - -interface WorkspaceEnvironments { - names: string[] -} - -interface WorkspaceQuickPick extends vscode.QuickPickItem { - fsPath: string; -} - -export async function workspaceQuickPick(): Promise { - try { - await GlobalFile.read(); - } - catch (e) { - let defaultConfig: GlobalConfig = { environments: [{ name: '', host: '', port: 0, user: '', password: '', sshLogin: '', serverType: 'SCA$IBS', encoding: 'utf8' }] } - await GlobalFile.write(defaultConfig); - await GlobalFile.show(); - return; - } - if (!vscode.workspace.workspaceFolders) return; - let workspaceFolders = vscode.workspace.workspaceFolders; - let items: WorkspaceQuickPick[] = await Promise.all(workspaceFolders.map(async folder => { - let name; - try { - let envObjects = await new WorkspaceFile(folder.uri.fsPath).environmentObjects; - if (envObjects.length === 1) { - name = '\u00a0 \u00a0 $(server) ' + envObjects[0].name - } - else if (envObjects.length > 1) { - name = '\u00a0 \u00a0 $(server) ' + envObjects.map(e => e.name).join(', ') - } - else { - name = '\u00a0 \u00a0 Not configured'; - } - } - catch (e) { - name = '\u00a0 \u00a0 Not configured'; - } - let item: WorkspaceQuickPick = { label: '$(file-directory) ' + folder.name, description: folder.uri.fsPath, detail: name, fsPath: folder.uri.fsPath } - return item; - })); - if (items.length === 1) return items[0]; - let configureEnvironments = '\u270E Edit Environments...'; - items.push({ label: configureEnvironments, description: '', fsPath: '' }); - let choice = await vscode.window.showQuickPick(items, { placeHolder: 'Select a Workspace.' }) - if (!choice) return; - if (choice.label === configureEnvironments) { - await GlobalFile.show(); - return; - } - return choice; -} - -async function configureEnvironmentHandler() { - let workspace = await workspaceQuickPick(); - if (!workspace) return; - environmentQuickPick(new WorkspaceFile(workspace.fsPath)); -} - -async function environmentQuickPick(workspaceFile: WorkspaceFile) { - let choice = undefined; - let workspaceEnvironments; - let globalConfig: GlobalConfig; - let names; - try { - globalConfig = await GlobalFile.read(); - } - catch (e) { - if (e === GlobalFile.INVALID_CONFIG) { - await GlobalFile.show(); - } - else { - - } - let defaultConfig: GlobalConfig = { environments: [{ name: '', host: '', port: 0, user: '', password: '', sshLogin: '' }] } - await GlobalFile.write(defaultConfig); - await GlobalFile.show(); - return; - } - - try { - workspaceEnvironments = await workspaceFile.environment; - names = workspaceEnvironments.names - } - catch (e) { - await workspaceFile.writeLocalEnv({'names': []}); - workspaceEnvironments = await workspaceFile.environment; - names = workspaceEnvironments.names; - } - do { - let items: vscode.QuickPickItem[] = globalConfig.environments.map(env => { - if (names.indexOf(env.name) > -1) { - return { label: `${env.name}`, description: '✔' } - } - return { label: `${env.name}`, description: '' } - }) - let configureEnvironments = '\u270E Edit Environments...'; - let back = '\u21a9 Back to Workspaces'; - items.push({ label: configureEnvironments, description: '' }) - if (vscode.workspace.workspaceFolders.length > 1) { - items.push({ label: back, description: '' }) - } - choice = await vscode.window.showQuickPick(items, { placeHolder: `Enable environments for ${workspaceFile.workspaceFolder.name}` }); - if (choice) { - if (choice.label === configureEnvironments) { - GlobalFile.show(); - break; - } - if (choice.label === back) { - configureEnvironmentHandler(); - break; - } - let index = names.indexOf(choice.label); - if (index > -1) { - names.splice(index, 1); - } - else names.push(choice.label); - workspaceFile.writeLocalEnv(workspaceEnvironments); - } - } while (choice); - await changeTextEditorHandler(vscode.window.activeTextEditor); -} - -async function changeTextEditorHandler(textEditor: vscode.TextEditor | undefined) { - let configureEnvironmentText = '$(server) Configure Environments'; - try { - let workspaceFile = new WorkspaceFile(textEditor.document.fileName); - let workspaceEnvironments = await workspaceFile.environment - if (workspaceEnvironments.names.length === 0) { - statusBar.text = configureEnvironmentText; - } - else if (workspaceEnvironments.names.length === 1) { - statusBar.text = '$(server) ' + workspaceEnvironments.names[0]; - } - else { - statusBar.text = '$(server) ' + workspaceEnvironments.names.length + ' environments'; - } - } - catch (e) { - statusBar.text = configureEnvironmentText; - } - statusBar.show(); -} - - - -export interface LaunchQuickPick extends vscode.QuickPickItem { - env: EnvironmentConfig; -} - -export class WorkspaceFile { - - /** - * The file system path of the file. - */ - readonly fsPath: string; - - /** - * The file system path of the file. - */ - readonly environmentPath: string; - - /** - * The file system path of the file. - */ - readonly workspaceFolder: vscode.WorkspaceFolder | undefined = undefined; - - /** - * Contents of local environment.json - */ - private _enviornment: WorkspaceEnvironments = undefined; - - /** - * Environment configurations from global environments.json - * corresponding to names in local environment.json - */ - private _environmentObjects: EnvironmentConfig[] = undefined; - - /** - * @param {string} fsPath The file system path of the file. - */ - constructor(fsPath: string) { - this.fsPath = fsPath; - - if (!fsPath) { - this.environmentPath = ''; - return; - } - - this.workspaceFolder = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(fsPath)); - if (!this.workspaceFolder) { - this.environmentPath = ''; - } - else { - this.environmentPath = path.join(this.workspaceFolder.uri.fsPath, LOCAL_ENV_DIR); - } - } - - /** - * Environment configurations from global environments.json - * corresponding to names in local environment.json - */ - get environmentObjects(): Promise { - if (this._environmentObjects) return Promise.resolve(this._environmentObjects); - return this.getEnvironmentObjects(); - } - - private async getEnvironmentObjects() { - let environment = await this.environment; - let globalEnv = await this.getEnvironmentFromGlobalConfig(environment.names); - this._environmentObjects = globalEnv; - return this._environmentObjects; - } - - /** - * - * @param nameArray An array of names to match the names of configurations in the GlobalConfig. - */ - private async getEnvironmentFromGlobalConfig(nameArray: string[]): Promise { - let allEnvs = (await GlobalFile.read()).environments; - let ret: EnvironmentConfig[] = [] - for (let name of nameArray) { - for (let env of allEnvs) { - if (env.name === name) { - ret.push(env); - } - } - } - return ret; - } - - /** - * Contents of local environment.json - */ - get environment(): Promise { - if (this._enviornment) return Promise.resolve(this._enviornment); - return fs.readFile(this.environmentPath).then(async file => { - let localEnvironment: WorkspaceEnvironments = jsonc.parse(file.toString()); - if (!localEnvironment.names || !Array.isArray(localEnvironment.names)) { - throw new Error('Local environment.json is not properly configured.'); - } - this._enviornment = localEnvironment; - return localEnvironment; - }) - } - - async writeLocalEnv(newLocalEnv: WorkspaceEnvironments) { - // TODO prune names - await fs.ensureFile(this.environmentPath); - await fs.writeFile(this.environmentPath, JSON.stringify(newLocalEnv, null, '\t')); - } -} - -export class GlobalFile { - - /** - * Path to the global config file - */ - private static readonly path = (() => { - const envFileName = 'environments.json'; - const appdata = process.env.APPDATA || (process.platform === 'darwin' ? process.env.HOME + '/Library/Application Support' : '/var/local'); - let channelPath: string; - if (vscode.env.appName.indexOf('Insiders') > 0) { - channelPath = 'Code - Insiders'; - } else { - channelPath = 'Code'; - } - let envPath = path.join(appdata, channelPath, 'User', envFileName); - // in linux, it may not work with /var/local, then try to use /home/myuser/.config - if ((process.platform === 'linux') && (!fs.existsSync(envPath))) { - envPath = path.join(os.homedir(), '.config/', channelPath, 'User', envFileName); - } - return envPath; - })(); - - static readonly INVALID_CONFIG = new Error('Missing environments in global config.'); - - /** - * Reads and returns the contents of the file. - * - * @throws An error if parsing fails or if improperly formatted. - */ - static async read(): Promise { - let globalConfig = jsonc.parse((await fs.readFile(this.path)).toString()); - if (!globalConfig.environments) throw this.INVALID_CONFIG; - return globalConfig; - } - - /** - * Writes the new configuration to the file. - * - * @param newGlobalConfig The new configuration. - */ - static async write(newGlobalConfig: GlobalConfig) { - await fs.ensureFile(this.path); - await fs.writeFile(this.path, JSON.stringify(newGlobalConfig, null, '\t')); - } - - /** - * Shows the configuration file in the editor window. - */ - static async show() { - await vscode.window.showTextDocument(vscode.Uri.file(this.path)); - } -} diff --git a/src/common/statusUtils.ts b/src/common/statusUtils.ts deleted file mode 100644 index d8c034b..0000000 --- a/src/common/statusUtils.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as vscode from 'vscode'; - -export function updateStatus(status: vscode.StatusBarItem, langs: Array) { - if (langs.length === 0) { - status.show(); - } - else if (vscode.window.activeTextEditor && langs.indexOf(vscode.window.activeTextEditor.document.languageId) >= 0) { - status.show(); - } - else { - status.hide(); - } -} \ No newline at end of file diff --git a/src/common/terminal.ts b/src/common/terminal.ts deleted file mode 100644 index 5f23298..0000000 --- a/src/common/terminal.ts +++ /dev/null @@ -1,111 +0,0 @@ -import * as vscode from 'vscode'; - -export async function activate(context: vscode.ExtensionContext) { - - context.subscriptions.push( - vscode.commands.registerCommand( - 'psl.stepIn', stepIn, - ), - ); - - context.subscriptions.push( - vscode.commands.registerCommand( - 'psl.stepOut', stepOut, - ), - ); - - context.subscriptions.push( - vscode.commands.registerCommand( - 'psl.stepOver', stepOver, - ), - ); - - context.subscriptions.push( - vscode.commands.registerCommand( - 'psl.sendToHostTerminal', sendToHostTerminal, - ), - ); - terminalSendSettings(); - - configureGtmDebug(context); -} - -async function terminalSendSettings() { - const pslTerminalCommands = ['psl.stepIn', 'psl.stepOut', 'psl.stepOver', 'psl.sendToHostTerminal']; - const terminalSettings = vscode.workspace.getConfiguration('terminal'); - const commandsToSkip: string[] | undefined = terminalSettings.get('integrated.commandsToSkipShell'); - if (commandsToSkip) { - const merged = commandsToSkip.concat(pslTerminalCommands); - const filteredMerge = merged.filter((item, pos) => merged.indexOf(item) === pos); - terminalSettings.update('integrated.commandsToSkipShell', filteredMerge, true); - } -} - -function stepIn() { - terminalSend('ZSTEP INTO:"W $ZPOS,! ZP @$ZPOS B"'); -} - -function stepOut() { - terminalSend('ZSTEP OUTOF:"W $ZPOS,! ZP @$ZPOS B"'); -} - -function stepOver() { - terminalSend('ZSTEP OVER:"W $ZPOS,! ZP @$ZPOS B"'); -} - -function sendToHostTerminal(text: string) { - terminalSend(text); -} - -function terminalSend(text: string) { - const activeTerminal: vscode.Terminal | undefined = vscode.window.activeTerminal; - if (activeTerminal) { - activeTerminal.show(); - activeTerminal.sendText(text, true); - } -} - -function configureGtmDebug(context: vscode.ExtensionContext) { - const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 901); - const commandName = 'psl.setGtmDebug'; - let gtmDebug = vscode.workspace.getConfiguration('psl').get('gtmDebugEnabled'); - - const set = () => { - if (gtmDebug) showInformation(context); - statusBar.text = `GT.M Debug ${gtmDebug ? '$(check)' : '$(circle-slash)'}`; - vscode.commands.executeCommand('setContext', 'psl.gtmDebug', gtmDebug); - }; - - set(); - context.subscriptions.push( - vscode.commands.registerCommand( - commandName, () => { - gtmDebug = !gtmDebug; - set(); - }, - ), - ); - - vscode.workspace.onDidChangeConfiguration(event => { - if (event.affectsConfiguration('psl.gtmDebugEnabled')) { - gtmDebug = true; - set(); - } - }); - - statusBar.command = commandName; - statusBar.tooltip = 'GT.M Debug hotkeys'; - statusBar.show(); -} - -async function showInformation(context: vscode.ExtensionContext) { - const doNotShow = context.globalState.get('gtmDebugShow'); - if (doNotShow) return; - const response = await vscode.window.showInformationMessage( - 'INTO Ctrl+Q | OVER Ctrl+W | OUTOF Ctrl+E', - 'Do not show again', - ); - if (response) { - context.globalState.update('gtmDebugShow', true); - } -} diff --git a/src/extension.ts b/src/extension.ts deleted file mode 100644 index 5a8cd52..0000000 --- a/src/extension.ts +++ /dev/null @@ -1,31 +0,0 @@ -import * as vscode from 'vscode'; - -import * as terminal from './common/terminal'; -import * as hostEnvironment from './common/environment'; -import * as hostCommands from './hostCommands/activate'; -import * as languageFeatures from './language/activate'; - -export const PSL_MODE: vscode.DocumentFilter = { language: 'psl', scheme: 'file' }; -export const BATCH_MODE: vscode.DocumentFilter = { language: 'profileBatch', scheme: 'file' }; -export const TRIG_MODE: vscode.DocumentFilter = { language: 'profileTrigger', scheme: 'file' }; -export const DATA_MODE: vscode.DocumentFilter = { language: 'profileData', scheme: 'file' }; -export const SERIAL_MODE: vscode.DocumentFilter = { language: 'profileSerialData', scheme: 'file'}; -export const TBL_MODE: vscode.DocumentFilter = { language: 'profileTable', scheme: 'file' }; -export const COL_MODE: vscode.DocumentFilter = { language: 'profileColumn', scheme: 'file' }; - - -export function activate(context: vscode.ExtensionContext) { - - hostCommands.activate(context); - - hostEnvironment.activate(context); - - terminal.activate(context); - - languageFeatures.activate(context); -} - - -// this method is called when your extension is deactivated -export function deactivate() { -} diff --git a/src/hostCommands/activate.ts b/src/hostCommands/activate.ts deleted file mode 100644 index de3c6d1..0000000 --- a/src/hostCommands/activate.ts +++ /dev/null @@ -1,78 +0,0 @@ -import * as path from 'path'; -import * as vscode from 'vscode'; - -import { compileAndLinkHandler } from './compileAndLink'; -import { getElementHandler, getTableHandler } from './get'; - -import { refreshElementHandler, refreshTableHandler } from './refresh'; -import { runPSLHandler } from './run'; -import { - coverageContext, registerCustomRunContext, runCoverageHandler, - runTestHandler, testContext, -} from './runCustom'; -import { sendElementHandler, sendTableHandler } from './send'; -import { testCompileHandler } from './testCompile'; - -const PROFILE_ELEMENTS = [ - '.FKY', - '.G', - '.IDX', - '.JFD', - '.M', - '.m', - '.PPL', - '.properties', - '.PROPERTIES', - '.PSLX', - '.pslx', - '.PSLXTRA', - '.pslxtra', - '.PSQL', - '.psql', - '.QRY', - '.RPT', - '.SCR', -]; - -export function activate(context: vscode.ExtensionContext) { - - registerProfileElementContext(); - registerCustomRunContext(); - - const commands = [ - { id: 'psl.getElement', callback: getElementHandler }, - { id: 'psl.getTable', callback: getTableHandler }, - { id: 'psl.refreshElement', callback: refreshElementHandler }, - { id: 'psl.sendElement', callback: sendElementHandler }, - { id: 'psl.testCompile', callback: testCompileHandler }, - { id: 'psl.compileAndLink', callback: compileAndLinkHandler }, - { id: 'psl.runPSL', callback: runPSLHandler }, - { id: 'psl.sendTable', callback: sendTableHandler }, - { id: 'psl.refreshTable', callback: refreshTableHandler }, - // Custom commands - // { id: 'psl.getCompiledCode', callback: getCompiledCodeHandler }, - { id: `psl.${testContext.command}`, callback: runTestHandler }, - { id: `psl.${coverageContext.command}`, callback: runCoverageHandler }, - ]; - - for (const command of commands) { - context.subscriptions.push( - vscode.commands.registerCommand( - command.id, command.callback, - ), - ); - } -} - -function registerProfileElementContext() { - if (vscode.window.activeTextEditor) setIsProfileElementContext(vscode.window.activeTextEditor); - vscode.window.onDidChangeActiveTextEditor(setIsProfileElementContext); -} - -function setIsProfileElementContext(textEditor: vscode.TextEditor) { - let isElement: boolean = false; - if (textEditor) { - isElement = PROFILE_ELEMENTS.indexOf(path.extname(textEditor.document.fileName)) >= 0; - } - vscode.commands.executeCommand('setContext', 'psl.isProfileElement', isElement); -} diff --git a/src/hostCommands/compileAndLink.ts b/src/hostCommands/compileAndLink.ts deleted file mode 100644 index a4ba244..0000000 --- a/src/hostCommands/compileAndLink.ts +++ /dev/null @@ -1,64 +0,0 @@ -import * as vscode from 'vscode'; -import * as path from 'path'; -import * as fs from 'fs-extra'; - -import * as utils from './hostCommandUtils'; -import * as environment from '../common/environment' - -const icon = utils.icons.LINK; - -export async function compileAndLinkHandler(context: utils.ExtensionCommandContext): Promise { - let c = utils.getFullContext(context); - if (c.mode === utils.ContextMode.FILE) { - return compileAndLink(c.fsPath).catch(() => { }); - } - else if (c.mode === utils.ContextMode.DIRECTORY) { - let files = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(c.fsPath), canSelectMany: true, openLabel: 'Compile and Link' }) - if (!files) return; - for (let fsPath of files.map(file => file.fsPath)) { - await compileAndLink(fsPath).catch(() => { }); - } - } - else { - let quickPick = await environment.workspaceQuickPick(); - if (!quickPick) return; - let chosenEnv = quickPick; - let files = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(chosenEnv.fsPath), canSelectMany: true, openLabel: 'Compile and Link' }) - if (!files) return; - for (let fsPath of files.map(file => file.fsPath)) { - await compileAndLink(fsPath).catch(() => { }); - } - } - return; -} - -async function compileAndLink(fsPath: string) { - if (!fs.statSync(fsPath).isFile()) return - let envs; - try { - envs = await utils.getEnvironment(fsPath); - } - catch (e) { - utils.logger.error(`${utils.icons.ERROR} ${icon} Invalid environment configuration.`); - return; - } - if (envs.length === 0) { - utils.logger.error(`${utils.icons.ERROR} ${icon} No environments selected.`); - return; - } - let promises = [] - await vscode.workspace.openTextDocument(fsPath).then(doc => doc.save()); - for (let env of envs) { - promises.push(utils.executeWithProgress(`${icon} ${path.basename(fsPath)} COMPILE AND LINK`, async () => { - utils.logger.info(`${utils.icons.WAIT} ${icon} ${path.basename(fsPath)} COMPILE AND LINK in ${env.name}`); - let connection = await utils.getConnection(env); - let output = await connection.compileAndLink(fsPath); - connection.close(); - if (output.includes('compile and link successful')) utils.logger.info(`${utils.icons.SUCCESS} ${icon} ${path.basename(fsPath)} COMPILE AND LINK ${env.name} successful`) - else utils.logger.error(`${utils.icons.ERROR} ${icon} ${output}`); - }).catch((e: Error) => { - utils.logger.error(`${utils.icons.ERROR} ${icon} error in ${env.name} ${e.message}`); - })) - } - await Promise.all(promises); -} diff --git a/src/hostCommands/get.ts b/src/hostCommands/get.ts deleted file mode 100644 index 8914718..0000000 --- a/src/hostCommands/get.ts +++ /dev/null @@ -1,306 +0,0 @@ -import * as vscode from 'vscode'; -import * as utils from './hostCommandUtils'; -import * as path from 'path'; -import * as fs from 'fs-extra'; -import * as environment from '../common/environment'; -import { MumpsVirtualDocument } from '../language/mumps'; - -const icon = utils.icons.GET; - -export async function getElementHandler(context: utils.ExtensionCommandContext): Promise { - let c = utils.getFullContext(context); - if (c.mode === utils.ContextMode.DIRECTORY) { - let input = await promptUserForComponent(); - if (input) return getElement(path.join(c.fsPath, input)).catch(() => { }); - } - else if (c.mode === utils.ContextMode.FILE) { - let workspace = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(c.fsPath)); - if (!workspace) { - // skeptical of this approach - return; - } - let input = await promptUserForComponent(); - if (!input) return; - let extension = path.extname(input).replace('.', ''); - let description = utils.extensionToDescription[extension] - let filters: { [name: string]: string[] } = {} - filters[description] = [extension] - let currentFolder = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(c.fsPath)) - if (!currentFolder) return; - let target - let defaultDir = DIR_MAPPINGS[extension]; - if (defaultDir) { - target = { fsPath: path.join(currentFolder.uri.fsPath, defaultDir, input) } - } - else { - let defaultUri = vscode.Uri.file(path.join(currentFolder.uri.fsPath, input)) - target = await vscode.window.showSaveDialog({ defaultUri, filters: filters }); - } - if (!target) return; - return getElement(target.fsPath).catch(() => { }); - } - else { - let quickPick = await environment.workspaceQuickPick(); - if (!quickPick) return; - let chosenEnv = quickPick; - let input = await promptUserForComponent(); - if (!input) return; - let extension = path.extname(input).replace('.', ''); - let description = utils.extensionToDescription[extension] - let filters: { [name: string]: string[] } = {} - filters[description] = [extension] - let target - let defaultDir = DIR_MAPPINGS[extension]; - if (defaultDir) { - target = { fsPath: path.join(chosenEnv.fsPath, defaultDir, input) } - } - else { - let defaultUri = vscode.Uri.file(path.join(chosenEnv.fsPath, input)) - target = await vscode.window.showSaveDialog({ defaultUri, filters: filters }); - } - if (!target) return; - return getElement(target.fsPath).catch(() => { }); - } - return; -} - -export async function getTableHandler(context: utils.ExtensionCommandContext) { - let c = utils.getFullContext(context); - if (c.mode === utils.ContextMode.DIRECTORY) { - let input = await promptUserForTable(); - if (input) return getTable(input, c.fsPath, c.fsPath).catch(() => { }); - } - else if (c.mode === utils.ContextMode.FILE) { - let workspace = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(c.fsPath)); - if (!workspace) { - // skeptical of this approach - return; - } - let tableName = await promptUserForTable(); - if (!tableName) return; - let tableDir = DIR_MAPPINGS['TABLE'] - let target; - if (tableDir) { - target = [{ fsPath: path.join(workspace.uri.fsPath, tableDir) }] - } - else { - target = await vscode.window.showOpenDialog({ defaultUri: workspace.uri, canSelectFiles: false, canSelectFolders: true, canSelectMany: false, filters: { 'Table Directory': [] } }); - } - if (!target) return; - return getTable(tableName, target[0].fsPath, workspace.uri.fsPath).catch(() => { }); - } - else { - let quickPick = await environment.workspaceQuickPick(); - if (!quickPick) return; - let chosenEnv = quickPick; - let tableName = await promptUserForTable(); - if (!tableName) return; - let tableDir = DIR_MAPPINGS['TABLE'] - let target; - if (tableDir) { - target = [{ fsPath: path.join(chosenEnv.description, tableDir) }] - } - else { - target = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(chosenEnv.description), canSelectFiles: false, canSelectFolders: true, canSelectMany: false, filters: { 'Table Directory': [] } }); - } - if (!target) return; - return getTable(tableName, target[0].fsPath, chosenEnv.description).catch(() => { }); - } - return; -} - -export async function getCompiledCodeHandler(context: utils.ExtensionCommandContext): Promise { - let c = utils.getFullContext(context); - if (c.mode === utils.ContextMode.FILE) { - return getCompiledCode(c.fsPath).catch(() => {}); - } - else if (c.mode === utils.ContextMode.DIRECTORY) { - let files = await vscode.window.showOpenDialog({defaultUri: vscode.Uri.file(c.fsPath), canSelectMany: true, openLabel: 'Refresh'}) - if (!files) return; - for (let fsPath of files.map(file => file.fsPath)) { - await getCompiledCode(fsPath).catch(() => {}); - } - } - else { - let quickPick = await environment.workspaceQuickPick(); - if (!quickPick) return; - let chosenEnv = quickPick; - let files = await vscode.window.showOpenDialog({defaultUri: vscode.Uri.file(chosenEnv.fsPath), canSelectMany: true, openLabel: 'Refresh'}) - if (!files) return; - for (let fsPath of files.map(file => file.fsPath)) { - await getCompiledCode(fsPath).catch(() => {}) - } - } - return; -} - -async function getCompiledCode(fsPath: string) { - if (!fs.statSync(fsPath).isFile()) return; - let env: environment.EnvironmentConfig; - const routineName = `${path.basename(fsPath).split('.')[0]}.m`; - return utils.executeWithProgress(`${icon} ${path.basename(fsPath)} GET`, async () => { - let envs; - try { - envs = await utils.getEnvironment(fsPath); - } - catch (e) { - utils.logger.error(`${utils.icons.ERROR} ${icon} Invalid environment configuration.`); - return; - } - if (envs.length === 0) { - utils.logger.error(`${utils.icons.ERROR} ${icon} No environments selected.`); - return; - } - let choice = await utils.getCommandenvConfigQuickPick(envs); - if (!choice) return; - env = choice; - utils.logger.info(`${utils.icons.WAIT} ${icon} ${routineName} GET COMPILED from ${env.name}`); - let doc = await vscode.workspace.openTextDocument(fsPath); - await doc.save(); - let connection = await utils.getConnection(env); - let output = await connection.get(routineName); - const uri = vscode.Uri.parse(`${MumpsVirtualDocument.schemes.compiled}:/${env.name}/${routineName}`); - const virtualDocument = new MumpsVirtualDocument(routineName, output, uri); - utils.logger.info(`${utils.icons.SUCCESS} ${icon} ${routineName} GET COMPILED from ${env.name} succeeded`); - connection.close(); - vscode.window.showTextDocument(virtualDocument.uri, {preview: false}); - }).catch((e: Error) => { - if (env && env.name) { - utils.logger.error(`${utils.icons.ERROR} ${icon} error in ${env.name} ${e.message}`); - } - else { - utils.logger.error(`${utils.icons.ERROR} ${icon} ${e.message}`); - } - }) -} - -async function getElement(fsPath: string) { - let env; - await utils.executeWithProgress(`${icon} ${path.basename(fsPath)} GET`, async () => { - let envs; - try { - envs = await utils.getEnvironment(fsPath); - } - catch (e) { - utils.logger.error(`${utils.icons.ERROR} ${icon} Invalid environment configuration.`); - return; - } - if (envs.length === 0) { - utils.logger.error(`${utils.icons.ERROR} ${icon} No environments selected.`); - return; - } - let choice = await utils.getCommandenvConfigQuickPick(envs); - if (!choice) return; - env = choice; - utils.logger.info(`${utils.icons.WAIT} ${icon} ${path.basename(fsPath)} GET from ${env.name}`); - let connection = await utils.getConnection(env); - let output = await connection.get(fsPath); - await fs.ensureDir(path.dirname(fsPath)) - await utils.writeFileWithSettings(fsPath, output); - utils.logger.info(`${utils.icons.SUCCESS} ${icon} ${path.basename(fsPath)} GET from ${env.name} succeeded`); - connection.close(); - await vscode.workspace.openTextDocument(fsPath).then(vscode.window.showTextDocument) - }).catch((e: Error) => { - if (env && env.name) { - utils.logger.error(`${utils.icons.ERROR} ${icon} error in ${env.name} ${e.message}`); - } - else { - utils.logger.error(`${utils.icons.ERROR} ${icon} ${e.message}`); - } - }) - return; -} - -async function getTable(tableName: string, targetDirectory: string, workpacePath: string) { - let env; - await utils.executeWithProgress(`${icon} ${tableName} TABLE GET`, async () => { - let envs; - try { - envs = await utils.getEnvironment(workpacePath); - } - catch (e) { - utils.logger.error(`${utils.icons.ERROR} ${icon} Invalid environment configuration.`); - return; - } - if (envs.length === 0) { - utils.logger.error(`${utils.icons.ERROR} ${icon} No environments selected.`); - return; - } - let choice = await utils.getCommandenvConfigQuickPick(envs); - if (!choice) return; - env = choice; utils.logger.info(`${utils.icons.WAIT} ${icon} ${tableName} TABLE GET from ${env.name}`); - let connection = await utils.getConnection(env); - let output = await connection.getTable(tableName.toUpperCase() + '.TBL'); - await fs.ensureDir(path.join(targetDirectory, tableName.toLowerCase())); - let tableFiles = (await fs.readdir(targetDirectory)).filter(f => f.startsWith(tableName)); - for (let file of tableFiles) { - await fs.remove(file); - } - const promises = output.split(String.fromCharCode(0)).map(content => { - const contentArray = content.split(String.fromCharCode(1)); - const fileName = contentArray[0]; - const fileContent = contentArray[1]; - return utils.writeFileWithSettings(path.join(targetDirectory, tableName.toLowerCase(), fileName), fileContent); - }); - await Promise.all(promises); - utils.logger.info(`${utils.icons.SUCCESS} ${icon} ${tableName} TABLE GET from ${env.name} succeeded`); - connection.close(); - }).catch((e: Error) => { - if (env && env.name) { - utils.logger.error(`${utils.icons.ERROR} ${icon} error in ${env.name} ${e.message}`); - } - else { - utils.logger.error(`${utils.icons.ERROR} ${icon} ${e.message}`); - } - }) - return; -} - -async function promptUserForComponent() { - let inputOptions: vscode.InputBoxOptions = { - prompt: 'Name of Component (with extension)', validateInput: (input: string) => { - if (!input) return; - let extension = path.extname(input) ? path.extname(input).replace('.', '') : 'No extension' - if (extension in utils.extensionToDescription) return ''; - return `Invalid extension (${extension})`; - } - }; - return vscode.window.showInputBox(inputOptions); -} - -async function promptUserForTable() { - let inputOptions: vscode.InputBoxOptions = { - prompt: 'Name of Table (no extension)', - validateInput: (value: string) => { - if (!value) return; - if (value.includes('.')) return 'Do not include the extension'; - } - }; - return vscode.window.showInputBox(inputOptions); -} - -const DIR_MAPPINGS = { - 'BATCH': 'dataqwik/batch', - 'COL': '', - 'DAT': 'data', - 'FKY': 'dataqwik/foreign_key', - // 'G': 'Global', - 'IDX': 'dataqwik/index', - 'JFD': 'dataqwik/journal', - 'm': 'routine', - 'PPL': '', - 'PROC': 'dataqwik/procedure', - 'properties': 'property', - 'PSL': '', - 'psl': '', - 'pslx': '', - 'pslxtra': '', - 'psql': '', - 'QRY': 'dataqwik/query', - 'RPT': 'dataqwik/report', - 'SCR': 'dataqwik/screen', - // TABLE not supported - 'TABLE': 'dataqwik/table', - 'TBL': '', - 'TRIG': 'dataqwik/trigger', -} diff --git a/src/hostCommands/hostCommandUtils.ts b/src/hostCommands/hostCommandUtils.ts deleted file mode 100644 index e842810..0000000 --- a/src/hostCommands/hostCommandUtils.ts +++ /dev/null @@ -1,154 +0,0 @@ -import * as fs from 'fs-extra'; -import * as vscode from 'vscode'; -export { extensionToDescription } from '../mtm/utils'; -import * as environment from '../common/environment'; -import { MtmConnection } from '../mtm/mtm'; - -const outputChannel = vscode.window.createOutputChannel('Profile Host'); - -export const logger = { - error: (message: string) => { - outputChannel.show(true); - outputChannel.appendLine(`[ERR!][${new Date().toTimeString().split(' ')[0]}] ${message.trim()}\n`); - }, - info: (message: string, hide?: boolean) => { - if (!hide) outputChannel.show(true); - outputChannel.appendLine(`[INFO][${new Date().toTimeString().split(' ')[0]}] ${message.trim()}\n`); - }, - -}; - -export const enum icons { - ERROR = '❌', - GET = '⇩', - LINK = '🔗', - REFRESH = '🔃', - RUN = '▶', - SEND = '⇧', - SUCCESS = '✔', - TEST = '⚙', - WAIT = '…', - WARN = '⚠', -} - -export const enum ContextMode { - FILE = 1, - DIRECTORY = 2, - EMPTY = 3, -} - -const enum NEWLINE_SETTING { - ALWAYS = 'always', - NEVER = 'never', -} - -export interface ExtensionCommandContext { - fsPath: string; - dialog: boolean; -} - -export interface HostCommandContext { - fsPath: string; - mode: ContextMode; -} - -export function getFullContext(context: ExtensionCommandContext | undefined): HostCommandContext { - let fsPath: string = ''; - let mode: ContextMode; - const activeTextEditor = vscode.window.activeTextEditor; - if (context && context.dialog) { - mode = ContextMode.EMPTY; - return { fsPath, mode }; - } - if ((!context || !context.fsPath) && activeTextEditor) { - fsPath = activeTextEditor.document.fileName; - mode = ContextMode.FILE; - return { fsPath, mode }; - } - else if (!context) { - mode = ContextMode.EMPTY; - return { fsPath, mode }; - } - else { - fsPath = context.fsPath; - mode = fs.lstatSync(fsPath).isFile() ? ContextMode.FILE : ContextMode.DIRECTORY; - return { fsPath, mode }; - } -} - -export async function executeWithProgress(message: string, task: () => Promise) { - return vscode.window.withProgress({ location: vscode.ProgressLocation.Window, title: message }, async () => { - await task(); - return; - }); -} - -export async function getConnection(env: environment.EnvironmentConfig): Promise { - const connection = new MtmConnection(env.serverType, env.encoding); - await connection.open(env.host, env.port, env.user, env.password); - return connection; -} - -export async function getEnvironment(fsPath: string): Promise { - const workspaceFile = new environment.WorkspaceFile(fsPath); - try { - const envs = await workspaceFile.environmentObjects; - envs.forEach(env => { - if (!env.host || !env.port || !env.user || !env.password) { - throw new Error(); - } - }); - return envs; - } - catch (e) { - const workspaceFolder = workspaceFile.workspaceFolder; - if (workspaceFolder) { - throw new Error(`Invalid configuration for Workspace Folder ${workspaceFolder.name}`); - } - throw new Error(`File ${fsPath} is not a member of the Workspace.`); - } -} - -export async function getCommandenvConfigQuickPick(envs: environment.EnvironmentConfig[]): Promise { - const items: environment.LaunchQuickPick[] = envs.map(env => { - return { label: env.name, description: '', env }; - }); - if (items.length === 1) return items[0].env; - const choice = await vscode.window.showQuickPick(items, { placeHolder: 'Select environment to get from.' }); - if (!choice) return undefined; - return choice.env; -} - -export function writeFileWithSettings(fsPath: string, output: string): Promise { - const trailingNewline: NEWLINE_SETTING = vscode.workspace.getConfiguration('psl', vscode.Uri.file(fsPath)).get('trailingNewline'); - switch (trailingNewline) { - case NEWLINE_SETTING.ALWAYS: - if (!output.endsWith('\n')) output += detectNewline(output); - break; - case NEWLINE_SETTING.NEVER: - output = output.replace(/(\r?\n)+$/, ''); - break; - default: - break; - } - return fs.writeFile(fsPath, output); -} - -/** - * https://github.com/sindresorhus/detect-newline - */ -function detectNewline(output: string) { - const newlines = (output.match(/(?:\r?\n)/g) || []); - - if (newlines.length === 0) { - return '\n'; - } - - const crlfCount = newlines.filter(el => { - return el === '\r\n'; - }).length; - - const lfCount = newlines.length - crlfCount; - - return crlfCount > lfCount ? '\r\n' : '\n'; -} diff --git a/src/hostCommands/pslUnitTest.ts b/src/hostCommands/pslUnitTest.ts deleted file mode 100644 index a73fb36..0000000 --- a/src/hostCommands/pslUnitTest.ts +++ /dev/null @@ -1,228 +0,0 @@ -import * as vscode from 'vscode'; -import { EnvironmentConfig } from '../common/environment'; -import { getVirtualDocument, MumpsVirtualDocument, onDidDeleteVirtualMumps } from '../language/mumps'; -import { getConnection } from './hostCommandUtils'; - -export interface RoutineCoverage { - methods: MethodCoverage[]; - coverage: string; - name: string; -} - -interface MethodCoverage { - name: string; - coverageSequence: LineCoverage[]; -} - -interface LineCoverage { - indicator: CoverageIndicator; -} - -enum CoverageIndicator { - NOT_COVERED = 0, - COVERED = 1, - COMMENT = 2, -} - -interface ParsedOutput { - /** - * Output without coverage information. - */ - output: string; - - /** - * Parsed coverage information for a series of routines. - */ - documents: RoutineCoverage[]; -} - -const diagnosticCollection = vscode.languages.createDiagnosticCollection('psl-test'); - -const coverageScheme = MumpsVirtualDocument.schemes.coverage; - -function createDecoration(backgroundKey: string, rulerKey: string) { - return vscode.window.createTextEditorDecorationType({ - backgroundColor: new vscode.ThemeColor(backgroundKey), - isWholeLine: true, - overviewRulerColor: new vscode.ThemeColor(rulerKey), - overviewRulerLane: vscode.OverviewRulerLane.Full, - rangeBehavior: vscode.DecorationRangeBehavior.ClosedOpen, - }); -} -const notCovered = createDecoration('diffEditor.removedTextBackground', 'editorOverviewRuler.errorForeground'); -const covered = createDecoration('diffEditor.insertedTextBackground', 'diffEditor.insertedTextBackground'); - -onDidDeleteVirtualMumps(uri => { - if (uri.scheme === coverageScheme) { - diagnosticCollection.delete(uri); - } -}); - -vscode.window.onDidChangeActiveTextEditor(textEditor => { - if (textEditor && textEditor.document.uri.scheme === coverageScheme) { - setCoverageDecorations(textEditor); - } -}); - -export async function displayCoverage(documents: RoutineCoverage[], env: EnvironmentConfig, testName: string) { - const baseUri = vscode.Uri.parse(`${coverageScheme}:`); - const connection = await getConnection(env); - for (const documentCoverage of documents) { - await connection.get(`${documentCoverage.name}.m`).then(mCode => { - const sourceCode = mCode; - const uri = baseUri.with({ - path: `/${env.name}/${testName}/${documentCoverage.name}.m`, - query: JSON.stringify(documentCoverage), - }); - const virtualMumps = new MumpsVirtualDocument(documentCoverage.name, sourceCode, uri); - setCoverageDiagnostics(virtualMumps); - vscode.window.showTextDocument(virtualMumps.uri, { preview: false }); - }); - } -} - -function getRoutineCoverage(uri: vscode.Uri): RoutineCoverage { - return JSON.parse(uri.query); -} - -function setCoverageDiagnostics(virtualMumps: MumpsVirtualDocument) { - let allDiagnostics: vscode.Diagnostic[] = []; - getRoutineCoverage(virtualMumps.uri).methods.forEach(coverageMethod => { - const documentMethod = virtualMumps.parsedDocument.methods.find(method => { - return method.id.value === coverageMethod.name; - }); - if (!documentMethod) return; - const methodRanges = collectMethodRanges(coverageMethod); - const diagnostics = methodRanges.map(methodRange => { - const vscodeRange = new vscode.Range( - documentMethod.line + methodRange.start, - 0, - documentMethod.line + methodRange.end, - Number.MAX_VALUE, - ); - return new vscode.Diagnostic( - vscodeRange, - `Missing coverage in method "${coverageMethod.name}"`, - vscode.DiagnosticSeverity.Error, - ); - }); - allDiagnostics = [...allDiagnostics, ...diagnostics]; - }); - diagnosticCollection.set(virtualMumps.uri, allDiagnostics); -} - -function collectMethodRanges(methodCoverage: MethodCoverage) { - const ranges = []; - let previousIndicator: number; - interface SequenceRange { start: number; end: number; } - const last = methodCoverage.coverageSequence.reduce((range: SequenceRange, lineCoverage, index) => { - let indicator: number; - if (indicator === CoverageIndicator.COMMENT) indicator = previousIndicator; - else indicator = lineCoverage.indicator; - - if (indicator === CoverageIndicator.NOT_COVERED) { - if (!range) { - previousIndicator = indicator; - return { start: index, end: index }; - } - else { - previousIndicator = indicator; - range.end = index; - return range; - } - } - if (indicator === CoverageIndicator.COVERED && range) { - previousIndicator = indicator; - ranges.push(range); - } - }, undefined); - if (last) ranges.push(last); - return ranges; -} - -/** - * Called every time the document becomes active (`onDidChangeActiveTextEditor`) - * for the mumps coverage uri scheme. - */ -function setCoverageDecorations(textEditor: vscode.TextEditor) { - const notCoveredLines: number[] = []; - const coveredLines: number[] = []; - const virtualMumps = getVirtualDocument(textEditor.document.uri); - getRoutineCoverage(virtualMumps.uri).methods.forEach(coverageMethod => { - const documentMethod = virtualMumps.parsedDocument.methods.find(method => { - return method.id.value === coverageMethod.name; - }); - if (!documentMethod) return; - let lastIndicator: number; - for (let lineNumber = 0; lineNumber < coverageMethod.coverageSequence.length; lineNumber++) { - const indicator = coverageMethod.coverageSequence[lineNumber].indicator; - if (!indicator || (indicator === CoverageIndicator.COMMENT && !lastIndicator)) { - notCoveredLines.push(documentMethod.line + lineNumber); - lastIndicator = 0; - } - else { - coveredLines.push(documentMethod.line + lineNumber); - lastIndicator = 1; - } - } - }); - textEditor.setDecorations(notCovered, notCoveredLines.map(line => new vscode.Range(line, 0, line, Number.MAX_VALUE))); - textEditor.setDecorations(covered, coveredLines.map(line => new vscode.Range(line, 0, line, Number.MAX_VALUE))); -} - -/** - * Parses the RPC output of a coverage run. Returns sanitized output and parsed coverage report. - */ -export function parseCoverageOutput(input: string): ParsedOutput { - const parsed: ParsedOutput = { - documents: [], - output: input, - }; - - const begin = '#BeginCoverageInfo'; - const end = '#EndCoverageInfo'; - - if (!input.includes(begin) && !input.includes(end)) { - return parsed; - } - - const split1 = input.split(begin); - const split2 = split1[1].split(end); - const output = split1[0] + split2[split2.length - 1]; - parsed.output = output; - - const routinesToPercentages = new Map(); - - const match = output.match(/\d+\.\d+% - \w+/g); - if (!match) return parsed; - - match.forEach(l => routinesToPercentages.set((l.split(' - ')[1]), l.split(' - ')[0])); - - parsed.documents = extractDocumentCoverage(split2[0], routinesToPercentages); - - return parsed; -} - -function extractDocumentCoverage(codeOutput: string, routinesToPercentages: Map): RoutineCoverage[] { - const splitOutput = codeOutput.split(/\r?\n/).filter(x => x).map(x => x.trim()); - - const documents: RoutineCoverage[] = []; - let documentCoverage: RoutineCoverage = { coverage: '', methods: [], name: '' }; - const initialize = (routineName: string) => { - documentCoverage = { name: routineName, methods: [], coverage: routinesToPercentages.get(routineName) || '' }; - documents.push(documentCoverage); - }; - - for (const line of splitOutput) { - if (line.match(/^9\|.*/)) { - initialize(line.split('|')[1]); - } - else if (line.match(/^1/)) { - documentCoverage.methods.push( - { name: line.split('|')[1], coverageSequence: line.split('|')[2].split('').map(s => ({ indicator: Number(s) })) }, - ); - } - } - - return documents; -} diff --git a/src/hostCommands/refresh.ts b/src/hostCommands/refresh.ts deleted file mode 100644 index 7a6bfa0..0000000 --- a/src/hostCommands/refresh.ts +++ /dev/null @@ -1,122 +0,0 @@ -import * as vscode from 'vscode'; -import * as utils from './hostCommandUtils'; -import * as path from 'path'; -import * as fs from 'fs-extra'; -import * as environment from '../common/environment'; - -const icon = utils.icons.REFRESH; - -export async function refreshElementHandler(context: utils.ExtensionCommandContext): Promise { - let c = utils.getFullContext(context); - if (c.mode === utils.ContextMode.FILE) { - return refreshElement(c.fsPath).catch(() => {}); - } - else if (c.mode === utils.ContextMode.DIRECTORY) { - let files = await vscode.window.showOpenDialog({defaultUri: vscode.Uri.file(c.fsPath), canSelectMany: true, openLabel: 'Refresh'}) - if (!files) return; - for (let fsPath of files.map(file => file.fsPath)) { - await refreshElement(fsPath).catch(() => {}); - } - } - else { - let quickPick = await environment.workspaceQuickPick(); - if (!quickPick) return; - let chosenEnv = quickPick; - let files = await vscode.window.showOpenDialog({defaultUri: vscode.Uri.file(chosenEnv.fsPath), canSelectMany: true, openLabel: 'Refresh'}) - if (!files) return; - for (let fsPath of files.map(file => file.fsPath)) { - await refreshElement(fsPath).catch(() => {}) - } - } - return; -} - -async function refreshElement(fsPath: string) { - if (!fs.statSync(fsPath).isFile()) return; - let env; - return utils.executeWithProgress(`${icon} ${path.basename(fsPath)} REFRESH`, async () => { - let envs; - try { - envs = await utils.getEnvironment(fsPath); - } - catch (e) { - utils.logger.error(`${utils.icons.ERROR} ${icon} Invalid environment configuration.`); - return; - } - if (envs.length === 0) { - utils.logger.error(`${utils.icons.ERROR} ${icon} No environments selected.`); - return; - } - let choice = await utils.getCommandenvConfigQuickPick(envs); - if (!choice) return; - env = choice; - utils.logger.info(`${utils.icons.WAIT} ${icon} ${path.basename(fsPath)} REFRESH from ${env.name}`); - let doc = await vscode.workspace.openTextDocument(fsPath); - await doc.save(); - let connection = await utils.getConnection(env); - let output = await connection.get(fsPath); - await utils.writeFileWithSettings(fsPath, output); - utils.logger.info(`${utils.icons.SUCCESS} ${icon} ${path.basename(fsPath)} REFRESH from ${env.name} succeeded`); - connection.close(); - await vscode.window.showTextDocument(doc); - }).catch((e: Error) => { - if (env && env.name) { - utils.logger.error(`${utils.icons.ERROR} ${icon} error in ${env.name} ${e.message}`); - } - else { - utils.logger.error(`${utils.icons.ERROR} ${icon} ${e.message}`); - } - }) -} - -export async function refreshTableHandler(context: utils.ExtensionCommandContext) { - let c = utils.getFullContext(context); - if (c.mode === utils.ContextMode.FILE) { - let tableName: string; - if (path.extname(c.fsPath) === '.TBL') { - tableName = path.basename(c.fsPath).split('.TBL')[0]; - } - else if (path.extname(c.fsPath) === '.COL') { - tableName = path.basename(c.fsPath).split('.COL')[0].split('-')[0]; - } - else { - return; - } - let targetDir = path.dirname(c.fsPath); - return refreshTable(tableName, targetDir).catch(() => {}); - } -} - - -async function refreshTable(tableName: string, targetDirectory: string) { - let env; - await utils.executeWithProgress(`${icon} ${tableName} TABLE REFRESH`, async () => { - let envs = await utils.getEnvironment(targetDirectory); - let choice = await utils.getCommandenvConfigQuickPick(envs); - if (!choice) return; - env = choice; - utils.logger.info(`${utils.icons.WAIT} ${icon} ${tableName} TABLE REFRESH from ${env.name}`); - let connection = await utils.getConnection(env); - let output = await connection.getTable(tableName.toUpperCase() + '.TBL'); - let tableFiles = (await fs.readdir(targetDirectory)).filter(f => f.startsWith(tableName)); - for (let file of tableFiles) { - await fs.remove(file); - } - const promises = output.split(String.fromCharCode(0)).map(content => { - const contentArray = content.split(String.fromCharCode(1)); - const fileName = contentArray[0]; - const fileContent = contentArray[1]; - return utils.writeFileWithSettings(path.join(targetDirectory, fileName), fileContent); - }); - await Promise.all(promises); - utils.logger.info(`${utils.icons.SUCCESS} ${icon} ${tableName} TABLE REFRESH from ${env.name} succeeded`); - connection.close(); - }).catch((e: Error) => { - if (env && env.name) { - utils.logger.error(`${utils.icons.ERROR} ${icon} error in ${env.name} ${e.message}`); - } - else { - utils.logger.error(`${utils.icons.ERROR} ${icon} ${e.message}`); - } - }) -} diff --git a/src/hostCommands/run.ts b/src/hostCommands/run.ts deleted file mode 100644 index 2f80b7e..0000000 --- a/src/hostCommands/run.ts +++ /dev/null @@ -1,67 +0,0 @@ -import * as fs from 'fs-extra'; -import * as path from 'path'; -import * as vscode from 'vscode'; -import * as environment from '../common/environment'; -import * as utils from './hostCommandUtils'; - -const icon = utils.icons.RUN; - -export async function runPSLHandler(context: utils.ExtensionCommandContext): Promise { - handle(context); -} - -async function handle(context: utils.ExtensionCommandContext): Promise { - const c = utils.getFullContext(context); - if (c.mode === utils.ContextMode.FILE) { - return runPSL(c.fsPath).catch(() => { }); - } - else if (c.mode === utils.ContextMode.DIRECTORY) { - const files = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(c.fsPath), canSelectMany: true, openLabel: 'Run PSL' }); - if (!files) return; - for (const fsPath of files.map(file => file.fsPath)) { - await runPSL(fsPath).catch(() => { }); - } - } - else { - const quickPick = await environment.workspaceQuickPick(); - if (!quickPick) return; - const chosenEnv = quickPick; - const files = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(chosenEnv.fsPath), canSelectMany: true, openLabel: 'Run PSL' }); - if (!files) return; - for (const fsPath of files.map(file => file.fsPath)) { - await runPSL(fsPath).catch(() => { }); - } - } - return; -} - -async function runPSL(fsPath: string) { - if (!fs.statSync(fsPath).isFile()) return; - const doc = await vscode.workspace.openTextDocument(fsPath); - await doc.save(); - let envs: environment.EnvironmentConfig[]; - try { - envs = await utils.getEnvironment(fsPath); - } - catch (e) { - utils.logger.error(`${utils.icons.ERROR} ${icon} Invalid environment configuration.`); - return; - } - if (envs.length === 0) { - utils.logger.error(`${utils.icons.ERROR} ${icon} No environments selected.`); - return; - } - const promises = []; - for (const env of envs) { - promises.push(utils.executeWithProgress(`${icon} ${path.basename(fsPath)} RUN`, async () => { - utils.logger.info(`${utils.icons.WAIT} ${icon} ${path.basename(fsPath)} RUN in ${env.name}`); - const connection = await utils.getConnection(env); - const output: string = await connection.runPsl(fsPath); - connection.close(); - utils.logger.info(output.trim()); - }).catch((e: Error) => { - utils.logger.error(`${utils.icons.ERROR} ${icon} error in ${env.name} ${e.message}`); - })); - } - await Promise.all(promises); -} diff --git a/src/hostCommands/runCustom.ts b/src/hostCommands/runCustom.ts deleted file mode 100644 index 0a7cf6c..0000000 --- a/src/hostCommands/runCustom.ts +++ /dev/null @@ -1,150 +0,0 @@ -import * as fs from 'fs-extra'; -import * as path from 'path'; -import * as vscode from 'vscode'; -import * as environment from '../common/environment'; -import { MtmConnection } from '../mtm/mtm'; -import * as utils from './hostCommandUtils'; -import { displayCoverage, parseCoverageOutput, RoutineCoverage } from './pslUnitTest'; - -const icon = utils.icons.RUN; - -interface CustomRunContext { - command: string; - contextKey: string; -} - -export const testContext: CustomRunContext = { - command: 'runTest', - contextKey: 'psl.runTestContext', -}; - -export const coverageContext: CustomRunContext = { - command: 'runCoverage', - contextKey: 'psl.runCoverageContext', -}; - -const customRunContexts = [testContext, coverageContext]; - -interface CustomTaskConfig { - mrpcID: string; - request: string; - command: string; -} - -export async function runTestHandler(context: utils.ExtensionCommandContext): Promise { - handle(context, testContext); -} - -export async function runCoverageHandler(context: utils.ExtensionCommandContext): Promise { - handle(context, coverageContext); -} - -async function handle(context: utils.ExtensionCommandContext, runContext?: CustomRunContext): Promise { - const c = utils.getFullContext(context); - if (c.mode === utils.ContextMode.FILE) { - return runPSL(c.fsPath, runContext).catch(() => { }); - } - else if (c.mode === utils.ContextMode.DIRECTORY) { - const files = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(c.fsPath), canSelectMany: true, openLabel: 'Run PSL' }); - if (!files) return; - for (const fsPath of files.map(file => file.fsPath)) { - await runPSL(fsPath, runContext).catch(() => { }); - } - } - else { - const quickPick = await environment.workspaceQuickPick(); - if (!quickPick) return; - const chosenEnv = quickPick; - const files = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(chosenEnv.fsPath), canSelectMany: true, openLabel: 'Run PSL' }); - if (!files) return; - for (const fsPath of files.map(file => file.fsPath)) { - await runPSL(fsPath, runContext).catch(() => { }); - } - } - return; -} - -async function runPSL(fsPath: string, runContext: CustomRunContext) { - if (!fs.statSync(fsPath).isFile()) return; - const doc = await vscode.workspace.openTextDocument(fsPath); - const config = getFromConfiguration(doc.uri, runContext); - if (!config) throw new Error(`Invalid configuration for ${runContext.command}`); - await doc.save(); - let envs: environment.EnvironmentConfig[]; - try { - envs = await utils.getEnvironment(fsPath); - } - catch (e) { - utils.logger.error(`${utils.icons.ERROR} ${icon} Invalid environment configuration.`); - return; - } - if (envs.length === 0) { - utils.logger.error(`${utils.icons.ERROR} ${icon} No environments selected.`); - return; - } - const promises = []; - for (const env of envs) { - promises.push(utils.executeWithProgress(`${icon} ${path.basename(fsPath)} RUN`, async () => { - utils.logger.info(`${utils.icons.WAIT} ${icon} ${path.basename(fsPath)} RUN in ${env.name}`); - const connection = await utils.getConnection(env); - const output = await runCustom(connection, fsPath, config, env); - connection.close(); - utils.logger.info(output.trim()); - }).catch((e: Error) => { - utils.logger.error(`${utils.icons.ERROR} ${icon} error in ${env.name} ${e.message}`); - })); - } - await Promise.all(promises); -} - -function getFromConfiguration(uri: vscode.Uri, runContext: CustomRunContext): CustomTaskConfig | undefined { - const configs = vscode.workspace.getConfiguration('psl', uri).get('customTasks'); - const config = configs.find(c => c.command === runContext.command); - if (!config || !config.mrpcID || !config.request) { - return undefined; - } - return config; -} - -export function registerCustomRunContext() { - if (vscode.window.activeTextEditor) setCustomRunContext(vscode.window.activeTextEditor); - vscode.window.onDidChangeActiveTextEditor(setCustomRunContext); -} - -export function setCustomRunContext(textEditor: vscode.TextEditor) { - for (const context of customRunContexts) { - let showCommand = false; - if (textEditor) { - if (getFromConfiguration(textEditor.document.uri, context)) showCommand = true; - } - vscode.commands.executeCommand('setContext', context.contextKey, showCommand); - } -} - -async function runCustom( - connection: MtmConnection, - fsPath: string, - config: CustomTaskConfig, - env: environment.EnvironmentConfig, -): Promise { - - const output = await connection.runCustom(fsPath, config.mrpcID, config.request); - if (config.command !== coverageContext.command) return output; - const parsedOutput = parseCoverageOutput(output); - if (parsedOutput.documents.length) { - type QuickPickItem = vscode.QuickPickItem & { documentCoverage: RoutineCoverage }; - const items: QuickPickItem[] = parsedOutput.documents.map(documentCoverage => { - return { - description: documentCoverage.coverage, - documentCoverage, - label: documentCoverage.name, - }; - }); - vscode.window.showQuickPick(items, { canPickMany: true, placeHolder: 'Show coverage', ignoreFocusOut: true }) - .then(choices => { - if (!choices || !choices.length) return; - displayCoverage(choices.map(x => x.documentCoverage), env, path.basename(fsPath)); - }); - } - return parsedOutput.output; -} diff --git a/src/hostCommands/send.ts b/src/hostCommands/send.ts deleted file mode 100644 index 6a5dc58..0000000 --- a/src/hostCommands/send.ts +++ /dev/null @@ -1,117 +0,0 @@ -import * as vscode from 'vscode'; -import * as utils from './hostCommandUtils'; -import * as path from 'path'; -import * as fs from 'fs-extra'; -import * as environment from '../common/environment'; - -const icon = utils.icons.SEND; - -export async function sendElementHandler(context: utils.ExtensionCommandContext): Promise { - let c = utils.getFullContext(context); - if (c.mode === utils.ContextMode.EMPTY) { - let quickPick = await environment.workspaceQuickPick(); - if (!quickPick) return; - let chosenEnv = quickPick; - let files = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(chosenEnv.fsPath), canSelectMany: true, openLabel: 'Send' }) - if (!files) return; - for (let fsPath of files.map(file => file.fsPath).sort(tableFirst)) { - await sendElement(fsPath).catch(() => { }); - } - } - else if (c.mode === utils.ContextMode.DIRECTORY) { - let files = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(c.fsPath), canSelectMany: true, openLabel: 'Send' }); - if (!files) return; - let sortedFiles = files.map(uri => uri.fsPath).sort(tableFirst); - for (let fsPath of sortedFiles) { - await sendElement(fsPath).catch(() => { }); - } - } - if (c.mode === utils.ContextMode.FILE) { - return sendElement(c.fsPath).catch(() => { }); - } - return; -} - -export async function sendTableHandler(context: utils.ExtensionCommandContext): Promise { - let c = utils.getFullContext(context); - if (c.mode === utils.ContextMode.EMPTY) { - return; - } - if (c.mode === utils.ContextMode.FILE) { - let tableName: string; - if (path.extname(c.fsPath) === '.TBL') { - tableName = path.basename(c.fsPath).split('.TBL')[0]; - } - else if (path.extname(c.fsPath) === '.COL') { - tableName = path.basename(c.fsPath).split('.COL')[0].split('-')[0]; - } - else { - return; - } - let files = await fs.readdir(path.dirname(c.fsPath)) - let sortedFiles = files.filter(f => f.startsWith(tableName)).sort(tableFirst); - if (sortedFiles.length > 99) { - let resp = await vscode.window.showInformationMessage(`Send ${sortedFiles.length} elements of ${tableName}?`, { modal: true }, 'Yes'); - if (resp !== 'Yes') return; - } - for (let file of sortedFiles) { - await sendElement(path.join(path.dirname(c.fsPath), file)).catch(() => { }); - } - } - return; -} - -// async function sendDirectory(targetDir: string) { -// let fileNames = await fs.readdir(targetDir); -// let word = fileNames.length === 1 ? 'file' : 'files'; -// let resp = await vscode.window.showInformationMessage(`Send contents of ${targetDir} (${fileNames.length} ${word})?`, { modal: true }, 'Yes'); -// if (resp !== 'Yes') return; -// fileNames.sort(tableFirst); -// for (let index = 0; index < fileNames.length; index++) { -// let fileName = fileNames[index]; -// // TODO what if element is a directory? -// await sendElement(path.join(targetDir, fileName)); -// } -// } - -async function sendElement(fsPath: string) { - if (!fs.statSync(fsPath).isFile()) return - let envs; - try { - envs = await utils.getEnvironment(fsPath); - } - catch (e) { - utils.logger.error(`${utils.icons.ERROR} ${icon} Invalid environment configuration.`); - return; - } - if (envs.length === 0) { - utils.logger.error(`${utils.icons.ERROR} ${icon} No environments selected.`); - return; - } - let promises: Promise[] = [] - for (let env of envs) { - promises.push(utils.executeWithProgress(`${icon} ${path.basename(fsPath)} SEND`, async () => { - await vscode.workspace.openTextDocument(fsPath).then(doc => doc.save()) - utils.logger.info(`${utils.icons.WAIT} ${icon} ${path.basename(fsPath)} SEND to ${env.name}`); - let connection = await utils.getConnection(env); - await connection.send(fsPath); - connection.close(); - utils.logger.info(`${utils.icons.SUCCESS} ${icon} ${path.basename(fsPath)} SEND to ${env.name} successful`); - }).catch((e: Error) => { - utils.logger.error(`${utils.icons.ERROR} ${icon} error in ${env.name} ${e.message}`); - })) - }; - await Promise.all(promises); -} - -function tableFirst(a: string, b: string) { - let aIsTable = a.endsWith('.TBL'); - let bIsTable = b.endsWith('.TBL'); - if (aIsTable && !bIsTable) { - return -1; - } - else if (bIsTable && !aIsTable) { - return 1; - } - return a.localeCompare(b); -} \ No newline at end of file diff --git a/src/hostCommands/testCompile.ts b/src/hostCommands/testCompile.ts deleted file mode 100644 index c65e0be..0000000 --- a/src/hostCommands/testCompile.ts +++ /dev/null @@ -1,209 +0,0 @@ -import * as vscode from 'vscode'; -import * as utils from './hostCommandUtils'; -import * as path from 'path'; -import * as fs from 'fs-extra'; -import { PSLDiagnostic } from '../common/diagnostics'; -import * as extension from '../extension'; -import * as environment from '../common/environment'; - -const icon = utils.icons.TEST; - -export async function testCompileHandler(context: utils.ExtensionCommandContext): Promise { - let c = utils.getFullContext(context); - let diagnostics = [] - if (c.mode === utils.ContextMode.FILE) { - await testCompile(c.fsPath).catch(() => { }); - } - else if (c.mode === utils.ContextMode.DIRECTORY) { - let files = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(c.fsPath), canSelectMany: true, openLabel: 'Test Compile' }) - if (!files) return; - for (let fsPath of files.map(file => file.fsPath)) { - let result = await testCompile(fsPath).catch(() => { }); - if (result) diagnostics = diagnostics.concat(result); - } - } - else { - let quickPick = await environment.workspaceQuickPick(); - if (!quickPick) return; - let chosenEnv = quickPick; - let files = await vscode.window.showOpenDialog({ defaultUri: vscode.Uri.file(chosenEnv.fsPath), canSelectMany: true, openLabel: 'Test Compile' }) - if (!files) return; - for (let fsPath of files.map(file => file.fsPath)) { - let result = await testCompile(fsPath); - if (result) diagnostics = diagnostics.concat(result); - } - } -} - -export async function testCompile(fsPath: string): Promise { - const fileStats = await fs.stat(fsPath); - if (!fileStats.isFile()) { - utils.logger.error(`${utils.icons.ERROR} ${icon} ${fsPath} is not a file.`); - return true; - } - let textDocument = await vscode.workspace.openTextDocument(fsPath); - if (!canTestCompileFile(textDocument, fsPath)) { - // The error message for the specific error was already added in 'canTestCompileFile' - return true; - } - - let testCompileSucceeded = false; - let envs; - try { - envs = await utils.getEnvironment(fsPath); - } - catch (e) { - utils.logger.error(`${utils.icons.ERROR} ${icon} Invalid environment configuration.`); - return true; - } - if (envs.length === 0) { - utils.logger.error(`${utils.icons.ERROR} ${icon} No environments selected.`); - return true; - } - let testCompiles: Promise[] = []; - for (let env of envs) { - testCompiles.push(utils.executeWithProgress(`${icon} ${path.basename(fsPath)} TEST COMPILE`, async () => { - await textDocument.save(); - utils.logger.info(`${utils.icons.WAIT} ${icon} ${path.basename(fsPath)} TEST COMPILE in ${env.name}`); - let connection = await utils.getConnection(env); - let output = await connection.testCompile(fsPath); - connection.close(); - let pslDiagnostics = parseCompilerOutput(output, textDocument); - testCompileSucceeded = pslDiagnostics.filter(d => d.severity === vscode.DiagnosticSeverity.Error).length === 0; - let testCompileWarning = pslDiagnostics.filter(d => d.severity === vscode.DiagnosticSeverity.Warning).length > 0; - if (!testCompileSucceeded) { - output = `${utils.icons.ERROR} ${icon} ${path.basename(fsPath)} TEST COMPILE in ${env.name} failed\n` + output - } - else if (testCompileWarning) { - output = `${utils.icons.WARN} ${icon} ${path.basename(fsPath)} TEST COMPILE in ${env.name} succeeded with warning\n` + output - } - else { - output = `${utils.icons.SUCCESS} ${icon} ${path.basename(fsPath)} TEST COMPILE in ${env.name} succeeded\n` + output - } - utils.logger.info(output.split('\n').join('\n' + ' '.repeat(20))); - PSLDiagnostic.setDiagnostics(pslDiagnostics, env.name, fsPath); - }).catch((e: Error) => { - utils.logger.error(`${utils.icons.ERROR} ${icon} error in ${env.name} ${e.message}`); - })) - } - return false; -} - -function parseCompilerOutput(compilerOutput: string, document: vscode.TextDocument): PSLDiagnostic[] { - /* - ZFeatureToggleUtilities.PROC compiled at 15:31 on 29-05-17 - Source: ZFeatureToggleUtilities.PROC - - %PSL-E-SYNTAX: Missing #PROPERTYDEF - In module: ZFeatureToggleUtilities - - Source: ZFeatureToggleUtilities.PROC - #PROPEYDEF dummy class = String private node = "dummy" - %PSL-E-SYNTAX: Unexpected compiler command: PROPEYDEF - At source code line: 25 in subroutine: - - Source: ZFeatureToggleUtilities.PROC - - %PSL-I-LIST: 2 errors, 0 warnings, 0 informational messages ** failed ** - In module: ZFeatureToggleUtilities - */ - let outputArrays: Array = splitCompilerOutput(compilerOutput); - let pslDiagnostics: PSLDiagnostic[] = []; - outputArrays.slice(0, outputArrays.length - 1).forEach(pslCompilerMessage => { - - let lineNumber: number = pslCompilerMessage.getLineNumber(); - if (lineNumber - 1 > document.lineCount || lineNumber <= 0) return; - - let codeLine: string = document.lineAt(lineNumber - 1).text; - let startIndex: number = codeLine.search(/\S/); // returns the index of the first non-whitespace character - if (startIndex === -1) startIndex = 0; // codeLine is only whitespace characters - let range = new vscode.Range(lineNumber - 1, startIndex, lineNumber - 1, codeLine.length); - let severity = pslCompilerMessage.getSeverity(); - if (severity >= 0) { - pslDiagnostics.push(new PSLDiagnostic(`${pslCompilerMessage.message}`, severity, document.fileName, range)); - } - }); - return pslDiagnostics; -} - -function canTestCompileFile(document: vscode.TextDocument, fsPath: string): boolean { - let compilable: boolean = false; - if (vscode.languages.match(extension.PSL_MODE, document)) { - compilable = true; - } - else { - let fileTypeDescription = ""; - if (vscode.languages.match(extension.BATCH_MODE, document)) { - fileTypeDescription = "Batch" - } - else if (vscode.languages.match(extension.COL_MODE, document)) { - fileTypeDescription = "Column Definition" - } - else if (vscode.languages.match(extension.DATA_MODE, document)) { - fileTypeDescription = "Data File" - } - else if (vscode.languages.match(extension.SERIAL_MODE, document)) { - fileTypeDescription = "Serialized Data"; - } - else if (vscode.languages.match(extension.TBL_MODE, document)) { - fileTypeDescription = "Table Definition" - } - else if (vscode.languages.match(extension.TRIG_MODE, document)) { - fileTypeDescription = "Trigger" - } - if (fileTypeDescription != "") { - utils.logger.error(`${utils.icons.ERROR} ${icon} ${fileTypeDescription} ${path.basename(fsPath)} cannot be test compiled.`); - } - else { - utils.logger.error(`${utils.icons.ERROR} ${icon} ${path.basename(fsPath)} is not a PSL file.`); - } - } - return compilable; -} - -class PSLCompilerMessage { - source: string - code: string - message: string - location: string - - isFilled(): boolean { - return (this.source && this.message && this.location) !== ''; - } - getLineNumber(): number { - if (this.location.startsWith('In module:')) return -1; - return parseInt(this.location.replace('At source code line: ', '').split(' ')[0]); - } - getSeverity(): vscode.DiagnosticSeverity { - if (this.message.startsWith('%PSL-W-')) { - return vscode.DiagnosticSeverity.Warning; - } - else if (this.message.startsWith('%PSL-E-')) { - return vscode.DiagnosticSeverity.Error; - } - else if (this.message.startsWith('%PSL-I-')) { - return vscode.DiagnosticSeverity.Information; - } - return -1; - } -} - -function splitCompilerOutput(compilerOutput: string): Array { - /** - * breaks apart the psl compiler output string into an arrays of compiler messages - */ - let outputArrays: Array = []; - let compilerMessage: PSLCompilerMessage; - - let splitCompilerOutput = compilerOutput.replace(/\r/g, '').trim().split('\n'); - for (let i = 1; i < splitCompilerOutput.length; i++) { - compilerMessage = new PSLCompilerMessage(); - compilerMessage.source = splitCompilerOutput[i]; - compilerMessage.code = splitCompilerOutput[i + 1]; - compilerMessage.message = splitCompilerOutput[i + 2]; - compilerMessage.location = splitCompilerOutput[i + 3]; - if (compilerMessage.isFilled()) outputArrays.push(compilerMessage); - i = i + 4; - } - return outputArrays; -} diff --git a/src/language/activate.ts b/src/language/activate.ts deleted file mode 100644 index bd53153..0000000 --- a/src/language/activate.ts +++ /dev/null @@ -1,117 +0,0 @@ -import * as vscode from 'vscode'; - -import { BATCH_MODE, DATA_MODE, PSL_MODE, TRIG_MODE } from '../extension'; - -import * as codeQuality from './codeQuality'; -import { DataDocumentHighlightProvider, DataHoverProvider } from './dataItem'; -import { MumpsDocumentProvider, MumpsVirtualDocument } from './mumps'; -import * as previewDocumentation from './previewDocumentation'; -import { PSLDefinitionProvider } from './pslDefinitionProvider'; -import { MumpsDocumentSymbolProvider, PSLDocumentSymbolProvider } from './pslDocument'; -import { PSLHoverProvider } from './pslHoverProvider'; -import { PSLSignatureHelpProvider } from './pslSignature'; -import { PSLCompletionItemProvider } from './pslSuggest'; -import { setConfig, removeConfig } from '../parser/config'; - -export async function activate(context: vscode.ExtensionContext) { - - const PSL_MODES = [PSL_MODE, BATCH_MODE, TRIG_MODE]; - const MUMPS_MODES: vscode.DocumentFilter[] = Object.values(MumpsVirtualDocument.schemes).map(scheme => ({ scheme })); - - context.subscriptions.push( - // Data Hovers - vscode.languages.registerHoverProvider( - DATA_MODE, new DataHoverProvider(), - ), - - // Data Document Highlights - vscode.languages.registerDocumentHighlightProvider( - DATA_MODE, new DataDocumentHighlightProvider(), - ), - ); - - PSL_MODES.forEach(pslMode => { - context.subscriptions.push( - // Document Symbol Outline - vscode.languages.registerDocumentSymbolProvider( - pslMode, new PSLDocumentSymbolProvider(), - ), - - // Completion Items - vscode.languages.registerCompletionItemProvider( - pslMode, new PSLCompletionItemProvider(), '.', - ), - - // Signature Help - vscode.languages.registerSignatureHelpProvider( - pslMode, new PSLSignatureHelpProvider(), '(', ',', - ), - - // Go-to Definitions - vscode.languages.registerDefinitionProvider( - pslMode, new PSLDefinitionProvider(), - ), - - // Hovers - vscode.languages.registerHoverProvider( - pslMode, new PSLHoverProvider(), - ), - ); - }); - - MUMPS_MODES.forEach(mumpsMode => { - context.subscriptions.push( - // Content provider for virtual documents - vscode.workspace.registerTextDocumentContentProvider( - mumpsMode.scheme, new MumpsDocumentProvider(), - ), - - // Document Symbol Outline - vscode.languages.registerDocumentSymbolProvider( - mumpsMode, new MumpsDocumentSymbolProvider(), - ), - ); - }); - - projectActivate(context); - codeQuality.activate(context); - - previewDocumentation.activate(context); - - // Language Configuration - const wordPattern = /(-?\d*\.\d[a-zA-Z0-9\%\#]*)|([^\`\~\!\@\^\&\*\(\)\-\=\+\[\{\]\}\\\|\"\;\:\'\'\,\.\<\>\/\?\s_]+)/g; - vscode.languages.setLanguageConfiguration('psl', { wordPattern }); - vscode.languages.setLanguageConfiguration('profileBatch', { wordPattern }); - vscode.languages.setLanguageConfiguration('profileTrigger', { wordPattern }); -} - -export function previewEnabled(uri: vscode.Uri) { - return vscode.workspace.getConfiguration('psl', uri).get('previewFeatures'); -} - -async function projectActivate(context: vscode.ExtensionContext) { - const workspaces = new Map(); - if (vscode.workspace.workspaceFolders) { - vscode.workspace.workspaceFolders.forEach(workspace => { - workspaces.set(workspace.name, workspace.uri.fsPath); - }); - } - return Promise.all( - vscode.workspace.workspaceFolders - .map(workspace => new vscode.RelativePattern(workspace, 'profile-project.json')) - .map(async pattern => { - const watcher = vscode.workspace.createFileSystemWatcher(pattern); - context.subscriptions.push(watcher.onDidChange(uri => { - setConfig(uri.fsPath, workspaces); - }), watcher.onDidCreate(uri => { - setConfig(uri.fsPath, workspaces); - })); - watcher.onDidDelete(uri => { - removeConfig(uri.fsPath); - }); - const uris = await vscode.workspace.findFiles(pattern); - if (!uris.length) return; - await setConfig(uris[0].fsPath, workspaces); - }), - ); -} diff --git a/src/language/codeAction.ts b/src/language/codeAction.ts deleted file mode 100644 index 0f6ce44..0000000 --- a/src/language/codeAction.ts +++ /dev/null @@ -1,100 +0,0 @@ -import * as vscode from 'vscode'; -import { MemberDiagnostic } from '../language/codeQuality'; -import * as parser from '../parser/parser'; -import { getLineAfter } from '../parser/utilities'; -import { MethodDocumentation, MethodSeparator } from '../pslLint/methodDoc'; - -function initializeAction(title: string, ...diagnostics: MemberDiagnostic[]) { - const action = new vscode.CodeAction(title, vscode.CodeActionKind.QuickFix); - action.edit = new vscode.WorkspaceEdit(); - if (diagnostics) action.diagnostics = diagnostics; - return action; -} - -/* NOTE: -The CodeQualityActionContext is used in the provideCodeActions implementation of the -PSLActionProvider. This interface has a list of MemberDiagnostics, which extend -the vscode.Diagnostic interface. The provideCodeActions method expects an object that -implements the vscode.CodeActionContext interface. Ths interface now also has a triggerKind -and only property. These are not used currently, but this is fixing compilation errors. - -It might be worth revisiting all the custom interfaces that are extremely similar to -exposed vscode interfaces. -*/ -interface CodeQualityActionContext { - readonly triggerKind: vscode.CodeActionTriggerKind; - readonly only: vscode.CodeActionKind | undefined; - diagnostics: MemberDiagnostic[]; -} - -export class PSLActionProvider implements vscode.CodeActionProvider { - public async provideCodeActions( - document: vscode.TextDocument, - _range: vscode.Range | vscode.Selection, - context: CodeQualityActionContext, - _token: vscode.CancellationToken - ): Promise { - - if (context.diagnostics.length === 0) return; - - const newLine = document.eol === vscode.EndOfLine.LF ? '\n' : '\r\n'; - const actions: vscode.CodeAction[] = []; - const allDiagnostics: MemberDiagnostic[] = []; - const allTextEdits: Array<{ edit: vscode.TextEdit, priority: number }> = []; - - const fixAll: vscode.CodeAction = initializeAction('Fix all.'); - - for (const diagnostic of context.diagnostics) { - if (!diagnostic.member) continue; - - const method = diagnostic.member as parser.Method; - - if (diagnostic.ruleName === MethodSeparator.name) { - const separatorAction = initializeAction('Add separator.', diagnostic); - - const textEdit = vscode.TextEdit.insert( - new vscode.Position(method.id.position.line - 1, Number.MAX_VALUE), - `${newLine}\t// ---------------------------------------------------------------------`, - ); - - separatorAction.edit.set(document.uri, [textEdit]); - actions.push(separatorAction); - - allDiagnostics.push(diagnostic); - allTextEdits.push({ edit: textEdit, priority: 2 }); - } - - if (diagnostic.ruleName === MethodDocumentation.name) { - const documentationAction = initializeAction('Add documentation block.', diagnostic); - - let docText = `\t/* DOC -----------------------------------------------------------------${newLine}\t` - + `TODO: description of label ${method.id.value}${newLine}${newLine}`; - const terminator = `\t** ENDDOC */${newLine}`; - if (method.parameters.length > 0) { - const spacing = method.parameters.slice().sort((p1, p2): number => { - return p2.id.value.length - p1.id.value.length; - })[0].id.value.length + 2; - - docText += method.parameters.map(p => { - return `\t@param ${p.id.value}${' '.repeat(spacing - p.id.value.length)}TODO: description of param ${p.id.value}`; - }).join(`${newLine}${newLine}`) + `${newLine}`; - } - docText += terminator; - - const textEdit = vscode.TextEdit.insert(new vscode.Position(getLineAfter(method), 0), docText); - documentationAction.edit.set(document.uri, [textEdit]); - actions.push(documentationAction); - - allDiagnostics.push(diagnostic); - allTextEdits.push({ edit: textEdit, priority: 2 }); - - } - } - if (actions.length > 1) { - fixAll.edit.set(document.uri, allTextEdits.sort((a, b) => a.priority - b.priority).map(edits => edits.edit)); - fixAll.diagnostics = allDiagnostics; - actions.push(fixAll); - } - return actions; - } -} diff --git a/src/language/codeQuality.ts b/src/language/codeQuality.ts deleted file mode 100644 index 4ea1869..0000000 --- a/src/language/codeQuality.ts +++ /dev/null @@ -1,153 +0,0 @@ -import * as vscode from 'vscode'; -import { BATCH_MODE, PSL_MODE, TRIG_MODE } from '../extension'; -import * as parser from '../parser/parser'; -import { getDiagnostics } from '../pslLint/activate'; -import * as api from '../pslLint/api'; -import { getConfig, removeConfig, setConfig } from '../pslLint/config'; -import { PSLActionProvider } from './codeAction'; - -type lintOption = 'none' | 'all' | 'config' | true; - -export async function activate(context: vscode.ExtensionContext) { - - await pslLintConfigurationWatchers(context); - - const lintDiagnostics = vscode.languages.createDiagnosticCollection('psl-lint'); - context.subscriptions.push(lintDiagnostics); - - // initial token - let tokenSource = new vscode.CancellationTokenSource(); - - if (vscode.window.activeTextEditor) { - prepareRules(vscode.window.activeTextEditor.document, lintDiagnostics, tokenSource.token); - } - - vscode.window.onDidChangeActiveTextEditor(e => { - if (!e) return; - prepareRules(e.document, lintDiagnostics, tokenSource.token); - }); - - vscode.workspace.onDidChangeTextDocument(e => { - if (!e) return; - tokenSource.cancel(); - tokenSource = new vscode.CancellationTokenSource(); - prepareRules(e.document, lintDiagnostics, tokenSource.token); - }); - - vscode.workspace.onDidCloseTextDocument(closedDocument => { - lintDiagnostics.delete(closedDocument.uri); - }); - - const actionProvider = new PSLActionProvider(); - - for (const mode of [PSL_MODE, BATCH_MODE, TRIG_MODE]) { - context.subscriptions.push( - vscode.languages.registerCodeActionsProvider( - mode, actionProvider, - ), - ); - } -} - -async function pslLintConfigurationWatchers(context: vscode.ExtensionContext) { - return Promise.all( - vscode.workspace.workspaceFolders - .map(workspace => new vscode.RelativePattern(workspace, 'psl-lint.json')) - .map(async pattern => { - const watcher = vscode.workspace.createFileSystemWatcher(pattern); - context.subscriptions.push(watcher.onDidChange(uri => { - setConfig(uri.fsPath); - }), watcher.onDidCreate(uri => { - setConfig(uri.fsPath); - })); - watcher.onDidDelete(uri => { - removeConfig(uri.fsPath); - }); - const uris = await vscode.workspace.findFiles(pattern); - if (!uris.length) return; - await setConfig(uris[0].fsPath); - }), - ); -} - -export class MemberDiagnostic extends vscode.Diagnostic { - member: parser.Member; - ruleName: string; -} - -function prepareRules( - textDocument: vscode.TextDocument, - lintDiagnostics: vscode.DiagnosticCollection, - cancellationToken: vscode.CancellationToken, -) { - if (!api.ProfileComponent.isProfileComponent(textDocument.fileName)) return; - - const lintConfigValue: lintOption = vscode.workspace.getConfiguration('psl', textDocument.uri).get('lint'); - - let useConfig = false; - if (lintConfigValue === 'config') { - // check if config exist first - const config = getConfig(textDocument.uri.fsPath); - if (!config) return; - useConfig = true; - } - else if (lintConfigValue !== 'all' && lintConfigValue !== true) { - lintDiagnostics.clear(); - return; - } - - process.nextTick(() => { - if (!cancellationToken.isCancellationRequested) { - lint(textDocument, useConfig, cancellationToken, lintDiagnostics); - } - }); -} - -function lint( - textDocument: vscode.TextDocument, - useConfig: boolean, cancellationToken: vscode.CancellationToken, - lintDiagnostics: vscode.DiagnosticCollection, -) { - const profileComponent: api.ProfileComponent = prepareDocument(textDocument); - const parsedDocument = api.ProfileComponent.isPsl(profileComponent.fsPath) ? - parser.parseText(textDocument.getText()) : undefined; - const diagnostics = getDiagnostics(profileComponent, parsedDocument, useConfig); - const memberDiagnostics = transform(diagnostics, textDocument.uri); - process.nextTick(() => { - if (!cancellationToken.isCancellationRequested) { - lintDiagnostics.set(textDocument.uri, memberDiagnostics); - } - }); -} - -function prepareDocument(textDocument: vscode.TextDocument) { - const getTextAtLine = (n: number) => textDocument.lineAt(n).text; - const profileComponent = new api.ProfileComponent(textDocument.uri.fsPath, textDocument.getText(), getTextAtLine); - return profileComponent; -} - -function transform(diagnostics: api.Diagnostic[], uri: vscode.Uri): MemberDiagnostic[] { - return diagnostics.map(pslLintDiagnostic => { - const r = pslLintDiagnostic.range; - const vscodeRange = new vscode.Range(r.start.line, r.start.character, r.end.line, r.end.character); - const memberDiagnostic = new MemberDiagnostic(vscodeRange, pslLintDiagnostic.message, pslLintDiagnostic.severity); - memberDiagnostic.source = pslLintDiagnostic.source; - memberDiagnostic.code = pslLintDiagnostic.code; - memberDiagnostic.ruleName = pslLintDiagnostic.ruleName; - if (pslLintDiagnostic.member) memberDiagnostic.member = pslLintDiagnostic.member; - if (pslLintDiagnostic.relatedInformation) { - memberDiagnostic.relatedInformation = pslLintDiagnostic.relatedInformation.map(x => { - return new vscode.DiagnosticRelatedInformation( - new vscode.Location(uri, - new vscode.Range(x.range.start.line, - x.range.start.character, - x.range.end.line, - x.range.end.character, - )), - x.message, - ); - }); - } - return memberDiagnostic; - }); -} diff --git a/src/language/dataItem.ts b/src/language/dataItem.ts deleted file mode 100644 index 0c6a08b..0000000 --- a/src/language/dataItem.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as path from 'path'; -import * as vscode from 'vscode'; -import * as jsonc from 'jsonc-parser'; -import * as fs from 'fs-extra' - -function getEnvBase(fileName: string) { - return vscode.workspace.getWorkspaceFolder(vscode.Uri.file(fileName)).uri.fsPath -} - -export class DataHoverProvider implements vscode.HoverProvider { - public async provideHover(document: vscode.TextDocument, position: vscode.Position): Promise { - - // array of column names - let columnNames: Array = document.lineAt(0).text.split('\t'); - - // the text up to the cursor - let textToPosition: string = document.getText(new vscode.Range(position.line, 0, position.line, position.character)); - - // position of current data item - let currentDataItemPosition: number = textToPosition.split('\t').length - 1; - - // full text of data item - let dataItemText = document.lineAt(position.line).text.split('\t')[currentDataItemPosition]; - - let prevTabPos: number = textToPosition.lastIndexOf('\t') + 1; - let nextTabPos: number = prevTabPos + dataItemText.length; - - if (currentDataItemPosition <= columnNames.length) { - let columnName = columnNames[currentDataItemPosition]; - let tableName = path.basename(document.fileName).replace('.DAT', '') - let fileName = `${tableName.toUpperCase()}-${columnName.toUpperCase()}.COL` - let link = path.join(getEnvBase(document.fileName), 'dataqwik', 'table', `${tableName.toLowerCase()}`, `${fileName}`) - let content; - if (!fs.existsSync(link)) { - content = new vscode.MarkdownString(`COLUMN: **${columnName}**`); - } - else { - let uri = vscode.Uri.file(link) - let tbl = await vscode.workspace.openTextDocument(uri); - let tblJSON = jsonc.parse(tbl.getText()) - content = new vscode.MarkdownString(`COLUMN: **[${columnName}](command:vscode.open?${encodeURIComponent(JSON.stringify(uri))})** (*${tblJSON['DES']}*)`); - } - content.isTrusted = true; - return new vscode.Hover(content, new vscode.Range(position.line, prevTabPos, position.line, nextTabPos)) - } - - return undefined; - } -} - -export class DataDocumentHighlightProvider implements vscode.DocumentHighlightProvider { - public async provideDocumentHighlights(document: vscode.TextDocument, position: vscode.Position): Promise { - // the text up to the cursor - let textToPosition: string = document.getText(new vscode.Range(position.line, 0, position.line, position.character)); - - // position of current data item - let currentDataItemPosition: number = textToPosition.split('\t').length - 1; - - let highlights: vscode.DocumentHighlight[] = []; - for (let lineNumber = 0; lineNumber < document.lineCount; lineNumber++) { - let text = document.lineAt(lineNumber).text - if (!text) continue; - let row = document.lineAt(lineNumber).text.split('\t') - let dataItemText = row[currentDataItemPosition]; - let textToPosition = row.slice(0, currentDataItemPosition + 1).join('\t') - let prevTabCol: number = textToPosition.lastIndexOf('\t') + 1; - let nextTabCol: number = prevTabCol + dataItemText.length; - let range = new vscode.Range(lineNumber, prevTabCol, lineNumber, nextTabCol) - document.validateRange(range) - let highlight = new vscode.DocumentHighlight(range, vscode.DocumentHighlightKind.Write) - highlights.push(highlight) - } - return highlights; - } - -} \ No newline at end of file diff --git a/src/language/lang.ts b/src/language/lang.ts deleted file mode 100644 index 8205d93..0000000 --- a/src/language/lang.ts +++ /dev/null @@ -1,116 +0,0 @@ -import * as fs from 'fs-extra'; -import * as jsonc from 'jsonc-parser'; -import * as path from 'path'; -import * as vscode from 'vscode'; -import * as parser from '../parser/parser'; -import { Token } from '../parser/tokenizer'; -import * as utils from '../parser/utilities'; - -export interface Documentation { - code: string; - markdown: string; -} - -export async function getDocumentation(result: utils.FinderResult, finder: utils.ParsedDocFinder): Promise { - const { fsPath, member } = result; - if (!member) { - // handle tables here - if (fsPath.endsWith('.TBL')) { - const text = await getWorkspaceDocumentText(fsPath); - const parsed = jsonc.parse(text); - const doc = text.split('}')[1]; - const tableName = path.basename(fsPath).split('.')[0]; - - return { code: '(table) ' + tableName, markdown: `${parsed.DES}\n\n${doc}` }; - } - } - else if (member.memberClass === parser.MemberClass.column) { - const typs = { - $: ['Number', 'column type: $ (Currency)'], - B: ['String', 'column type: B (Blob)'], - C: ['Number', 'column type: C (Time)'], - D: ['Date', 'column type: D (Date)'], - F: ['Number', 'column type: F (Frequency)'], - L: ['Boolean', 'column type: L (Logical)'], - M: ['String', 'column type: M (Memo)'], - N: ['Number', 'column type: N (Number)'], - T: ['String', 'column type: T (Text)'], - U: ['String', 'column type: U (Uppercase text)'], - }; - const text = await getWorkspaceDocumentText(fsPath); - const parsed = jsonc.parse(text); - const typ = parsed.TYP; - const doc = text.split('}')[1]; - - return { - code: `(column) ${typs[typ][0]} ${member.id.value}`, - markdown: `${parsed.DES}\n\n${typs[typ][1]}\n\n${doc}`, - }; - } - else if (member.memberClass === parser.MemberClass.method) { - const method = member as parser.Method; - - const sigArray: Token[] = [...method.modifiers, method.types[0], method.id]; - const sig: string = sigArray.filter(Boolean).map(t => t.value).join(' '); - const argString: string = method.parameters - .map(param => `${param.types[0].value} ${param.id.value}`) - .join('\n\u200B , '); - let code = ''; - if (method.parameters.length === 0) code = `${sig}(${argString})`; - else code = `${sig}(\n\u200B \u200B \u200B ${argString}\n\u200B )`; - const markdown = method.documentation ? method.documentation : ''; - return { code, markdown }; - } - else { - let code = ''; - - if (member.types.length === 0) code = `void ${member.id.value}`; - else if (member.types.length === 1) { - if (member.types[0] === member.id) code = `static ${member.id.value}`; - else code = `${member.types[0].value} ${member.id.value}`; - } - else { - code = `${member.types[0].value} ${member.id.value}( ${member.types.slice(1).map((t: any) => t.value).join(', ')})`; - } - - switch (member.memberClass) { - case parser.MemberClass.declaration: - code = ' type ' + code; - break; - case parser.MemberClass.parameter: - code = '(parameter) ' + code; - break; - case parser.MemberClass.property: - code = ' #PROPERTYDEF ' + code; - break; - default: - return; - } - - let markdown = result.member.documentation ? result.member.documentation : ''; - - if (member.types[0].value.startsWith('Record')) { - const tableName = member.types[0].value.replace('Record', ''); - const tableDirectory = await finder.resolveFileDefinitionDirectory(tableName); - if (tableDirectory) { - const tableLocation = path.join( - tableDirectory, - tableName.toUpperCase() + '.TBL', - ); - const text = await getWorkspaceDocumentText(tableLocation); - const parsed = jsonc.parse(text); - const doc = text.split('}')[1]; - - markdown = `${parsed.DES}\n\n${doc}`; - } - } - return { code, markdown }; - } - -} - -export async function getWorkspaceDocumentText(fsPath: string): Promise { - return fs.stat(fsPath).then(_ => { - return vscode.workspace.openTextDocument(fsPath).then(textDocument => textDocument.getText(), () => ''); - }).catch(() => ''); -} diff --git a/src/language/mumps.ts b/src/language/mumps.ts deleted file mode 100644 index f7113ed..0000000 --- a/src/language/mumps.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { EventEmitter, TextDocumentContentProvider, Uri, workspace } from 'vscode'; -import { ParsedDocument, parseText } from '../parser'; - -export class MumpsVirtualDocument { - - static readonly schemes = { - compiled: 'compiledMumps', - coverage: 'coverageMumps', - }; - - readonly parsedDocument: ParsedDocument; - - constructor( - readonly routineName: string, - readonly sourceCode: string, - /** - * Uri with scheme in `mumpsSchemes` - */ - readonly uri: Uri, - ) { - this.parsedDocument = parseText(sourceCode); - virtualDocuments.set(uri.toString(), this); - } -} - -export class MumpsDocumentProvider implements TextDocumentContentProvider { - provideTextDocumentContent(uri: Uri): string { - return getVirtualDocument(uri).sourceCode; - } -} - -export function getVirtualDocument(uri: Uri) { - return virtualDocuments.get(uri.toString()); -} - -function isScheme(uri: Uri) { - return Object.values(MumpsVirtualDocument.schemes).indexOf(uri.scheme) > -1; -} - -/** - * Virtual Documents keyed by the string the string representation of their `Uri`s - */ -const virtualDocuments = new Map(); - -const _onDidDeleteVirtualMumps = new EventEmitter(); -export const onDidDeleteVirtualMumps = _onDidDeleteVirtualMumps.event; - -workspace.onDidCloseTextDocument(textDocument => { - const uri = textDocument.uri; - if (isScheme(uri)) { - virtualDocuments.delete(uri.toString()); - _onDidDeleteVirtualMumps.fire(uri); - } -}); diff --git a/src/language/previewDocumentation.ts b/src/language/previewDocumentation.ts deleted file mode 100644 index 06aac85..0000000 --- a/src/language/previewDocumentation.ts +++ /dev/null @@ -1,71 +0,0 @@ -import * as path from 'path'; -import { xhr }from 'request-light'; -import * as vscode from 'vscode'; - -export function activate(context: vscode.ExtensionContext) { - context.subscriptions.push( - vscode.commands.registerTextEditorCommand( - 'psl.previewDocumentation', - preparePreview, - ), - ); - - checkForDocumentationServer(); - - vscode.workspace.onDidChangeConfiguration(event => { - if (!event.affectsConfiguration('psl')) return; - checkForDocumentationServer(); - }); -} - -function checkForDocumentationServer(): string { - const documentationServer: string = vscode.workspace.getConfiguration('psl', null).get('documentationServer'); - if (documentationServer) { - vscode.commands.executeCommand('setContext', 'psl.hasDocumentationServer', true); - return documentationServer; - } - else { - vscode.commands.executeCommand('setContext', 'psl.hasDocumentationServer', false); - return ''; - } -} - -async function preparePreview(textEditor: vscode.TextEditor) { - const documentationServer: string = checkForDocumentationServer(); - if (!documentationServer) return; - - const markdown = await getMarkdownFromApi( - textEditor.document.getText(), - path.basename(textEditor.document.fileName), - documentationServer, - ); - if (!markdown) return; - showPreview(markdown); -} - -async function showPreview(markdown: string) { - const untitledDoc = await vscode.workspace.openTextDocument({ language: 'markdown', content: markdown }); - vscode.commands.executeCommand('markdown.showPreview', untitledDoc.uri); -} - -async function getMarkdownFromApi(pslText: string, fileName: string, documentationServer: string) { - try { - const data: string = JSON.stringify({ - sourceText: pslText, - }); - const response = await xhr({ - data, - headers: { - 'Content-Length': `${Buffer.byteLength(data)}`, - 'Content-Type': 'application/json', - }, - type: 'POST', - url: documentationServer + fileName, - }); - return response.responseText; - } - catch (e) { - vscode.window.showErrorMessage(e.responseText); - return ''; - } -} diff --git a/src/language/pslDefinitionProvider.ts b/src/language/pslDefinitionProvider.ts deleted file mode 100644 index b302807..0000000 --- a/src/language/pslDefinitionProvider.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as vscode from 'vscode'; -import { FinderPaths, getFinderPaths } from '../parser/config'; -import * as parser from '../parser/parser'; -import * as utils from '../parser/utilities'; -import * as lang from './lang'; - -export class PSLDefinitionProvider implements vscode.DefinitionProvider { - - async provideDefinition(document: vscode.TextDocument, position: vscode.Position, cancellationToknen: vscode.CancellationToken): Promise { - if (cancellationToknen.isCancellationRequested) return; - let parsedDoc = parser.parseText(document.getText()); - - // get tokens on line and current token - let tokenSearchResults = utils.searchTokens(parsedDoc.tokens, position); - if (!tokenSearchResults) return []; - let { tokensOnLine, index } = tokenSearchResults; - - const workspaceDirectory = vscode.workspace.getWorkspaceFolder(document.uri); - if (!workspaceDirectory) return; - - let callTokens = utils.getCallTokens(tokensOnLine, index); - if (callTokens.length === 0) return; - let paths: FinderPaths = getFinderPaths(workspaceDirectory.uri.fsPath, document.fileName); - let finder = new utils.ParsedDocFinder(parsedDoc, paths, lang.getWorkspaceDocumentText); - let resolvedResult = await finder.resolveResult(callTokens); - if (resolvedResult) return getLocation(resolvedResult); - } -} - -function getLocation(result: utils.FinderResult): vscode.Location { - if (!result.member) { - return new vscode.Location(vscode.Uri.file(result.fsPath), new vscode.Position(0, 0)); - } - let range = result.member.id.getRange(); - let vscodeRange = new vscode.Range(range.start.line, range.start.character, range.end.line, range.end.character); - return new vscode.Location(vscode.Uri.file(result.fsPath), vscodeRange); -} diff --git a/src/language/pslDocument.ts b/src/language/pslDocument.ts deleted file mode 100644 index 3b6304d..0000000 --- a/src/language/pslDocument.ts +++ /dev/null @@ -1,61 +0,0 @@ -import * as vscode from 'vscode'; -import * as parser from '../parser/parser'; -import { getVirtualDocument } from './mumps'; - -export class PSLDocumentSymbolProvider implements vscode.DocumentSymbolProvider { - - public provideDocumentSymbols(document: vscode.TextDocument): Promise { - return new Promise(resolve => { - const parsedDoc = parser.parseText(document.getText()); - const symbols: vscode.SymbolInformation[] = []; - parsedDoc.methods.forEach(method => { - symbols.push(createMethodSymbol(method, document)); - }); - parsedDoc.properties.forEach(property => { - const propertyNameToken = property.id; - const name = propertyNameToken.value; - const containerName = ''; - const position = propertyNameToken.position; - const location = new vscode.Location(document.uri, new vscode.Position(position.line, position.character)); - symbols.push(new vscode.SymbolInformation(name, vscode.SymbolKind.Property, containerName, location)); - }); - resolve(symbols); - }); - } -} - -/** - * Outline provider for MUMPS - */ -export class MumpsDocumentSymbolProvider implements vscode.DocumentSymbolProvider { - - public provideDocumentSymbols(document: vscode.TextDocument): vscode.SymbolInformation[] { - const symbols: vscode.SymbolInformation[] = []; - const parsedDoc = this.getParsedDoc(document); - parsedDoc.methods.forEach(method => { - symbols.push(createMethodSymbol(method, document)); - }); - return symbols; - } - - getParsedDoc(document: vscode.TextDocument) { - const cachedMumps = getVirtualDocument(document.uri); - if (cachedMumps) return cachedMumps.parsedDocument; - else return parser.parseText(document.getText()); - } -} - -function createMethodSymbol(method: parser.Method, document: vscode.TextDocument) { - const methodToken = method.id; - const name = methodToken.value; - const containerName = ''; - - const startPosition = new vscode.Position(methodToken.position.line, 0); - - let endPositionNumber = method.endLine; - if (endPositionNumber === -1) endPositionNumber = document.lineCount - 1; // last line - const endPosition = new vscode.Position(endPositionNumber, 0); - const methodRange = new vscode.Location(document.uri, new vscode.Range(startPosition, endPosition)); - const kind = method.batch ? vscode.SymbolKind.Module : vscode.SymbolKind.Function; - return new vscode.SymbolInformation(name, kind, containerName, methodRange); -} diff --git a/src/language/pslFormat.ts b/src/language/pslFormat.ts deleted file mode 100644 index 0ca6658..0000000 --- a/src/language/pslFormat.ts +++ /dev/null @@ -1,79 +0,0 @@ -import * as vscode from 'vscode'; -import * as parser from '../parser/parser'; -import { PSL_MODE } from '../extension'; - -export function activate(context: vscode.ExtensionContext) { - - context.subscriptions.push( - vscode.languages.registerDocumentFormattingEditProvider( - PSL_MODE, new PSLFormatProvider() - ) - ); - -} - -export class PSLFormatProvider implements vscode.DocumentFormattingEditProvider { - provideDocumentFormattingEdits(document: vscode.TextDocument): Promise { - let textEdits: vscode.TextEdit[] = []; - return new Promise(resolve => { - let p = parser.parseText(document.getText()); - p.methods.forEach(method => { - if (!method.closeParen) return; - method.memberClass - let methodLine = method.id.position.line; - let closePosition = method.closeParen.position; - let methodRange = new vscode.Range(methodLine, 0, closePosition.line, closePosition.character + 1) - textEdits.push(new vscode.TextEdit(methodRange, buildText(method))); - }) - resolve(textEdits); - }) - } -} - -interface Param { - parameter: string - comment: string -} - -function buildText(method: parser.Method): string { - let methodString = ''; - if (method.modifiers.length > 0) { - methodString += method.modifiers.map(m => m.value).join(' ') + ' '; - } - - methodString += `${method.id.value}(`; - let parameterStrings: Param[] = method.parameters.map(p => { - let param = { parameter: '', comment: '' } - let parameterString = ''; - if (p.req) { - parameterString += 'req '; - } - if (p.ret) { - parameterString += 'ret '; - } - if (p.literal) { - parameterString += 'literal '; - } - parameterString += p.types[0].value + ' ' + p.id.value; - if (p.types.length > 1) { - parameterString += `( ${p.types.map(t => t.value).slice(1).join(', ')})`; - } - if (p.comment) { - param.comment = `\t// ${p.comment.value.trim()}` - } - param.parameter = parameterString - return param; - }) - if (parameterStrings.length === 0) { - methodString += ')'; - } - else if (parameterStrings.length === 1) { - methodString += parameterStrings[0].parameter + ')' + parameterStrings[0].comment; - } - else { - methodString += '\n\t\t ' + parameterStrings.map(p => p.parameter + p.comment).join('\n\t\t, '); - methodString += '\n\t\t)' - } - - return methodString; -} \ No newline at end of file diff --git a/src/language/pslHoverProvider.ts b/src/language/pslHoverProvider.ts deleted file mode 100644 index 417e531..0000000 --- a/src/language/pslHoverProvider.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as vscode from 'vscode'; -import { FinderPaths, getFinderPaths } from '../parser/config'; -import * as parser from '../parser/parser'; -import * as utils from '../parser/utilities'; -import * as lang from './lang'; - -export class PSLHoverProvider implements vscode.HoverProvider { - - async provideHover(document: vscode.TextDocument, position: vscode.Position, cancellationToken: vscode.CancellationToken): Promise { - if (cancellationToken.isCancellationRequested) return; - let parsedDoc = parser.parseText(document.getText()); - - // get tokens on line and current token - let tokenSearchResults = utils.searchTokens(parsedDoc.tokens, position); - if (!tokenSearchResults) return; - let { tokensOnLine, index } = tokenSearchResults; - - const workspaceDirectory = vscode.workspace.getWorkspaceFolder(document.uri); - if (!workspaceDirectory) return; - - let callTokens = utils.getCallTokens(tokensOnLine, index); - if (callTokens.length === 0) return; - let paths: FinderPaths = getFinderPaths(workspaceDirectory.uri.fsPath, document.fileName); - let finder = new utils.ParsedDocFinder(parsedDoc, paths, lang.getWorkspaceDocumentText); - let resolvedResult = await finder.resolveResult(callTokens); - if (resolvedResult) return getHover(resolvedResult, finder); - } -} - -async function getHover(result: utils.FinderResult, finder: utils.ParsedDocFinder): Promise { - let { code, markdown } = await lang.getDocumentation(result, finder); - - let clean = markdown.replace(/\s*(DOC)?\s*\-+/, '').replace(/\*+\s+ENDDOC/, '').trim(); - clean = clean - .split(/\r?\n/g).map(l => l.trim()).join('\n') - .replace(/(@\w+)/g, '*$1*') - .replace(/(\*(@(param|publicnew|public|throws?))\*)\s+([A-Za-z\-0-9%_\.]+)/g, '$1 `$4`'); - - return new vscode.Hover([new vscode.MarkdownString().appendCodeblock(code), new vscode.MarkdownString().appendMarkdown(clean)]); -} diff --git a/src/language/pslSignature.ts b/src/language/pslSignature.ts deleted file mode 100644 index 788baf6..0000000 --- a/src/language/pslSignature.ts +++ /dev/null @@ -1,67 +0,0 @@ -import * as vscode from 'vscode'; -import { FinderPaths, getFinderPaths } from '../parser/config'; -import * as parser from '../parser/parser'; -import { Position, Token } from '../parser/tokenizer'; -import * as utils from '../parser/utilities'; -import * as lang from './lang'; - -export class PSLSignatureHelpProvider implements vscode.SignatureHelpProvider { - public async provideSignatureHelp(document: vscode.TextDocument, position: vscode.Position): Promise { - const workspaceDirectory = vscode.workspace.getWorkspaceFolder(document.uri); - if (!workspaceDirectory) return; - - let parsedDoc = parser.parseText(document.getText()); - // get tokens on line and current token - let tokenSearchResults = ((tokens: Token[], position: Position) => { - const tokensOnLine = tokens.filter(t => t.position.line === position.line); - if (tokensOnLine.length === 0) return undefined; - const index = tokensOnLine.findIndex(t => { - const start: Position = t.position; - const end: Position = { line: t.position.line, character: t.position.character + t.value.length }; - const isBetween = (lb: Position, t: Position, ub: Position): boolean => { - return lb.line <= t.line && - lb.character <= t.character && - ub.line >= t.line && - ub.character >= t.character; - } - return isBetween(start, position, end); - }); - return { tokensOnLine, index }; - })(parsedDoc.tokens, position); - - if (!tokenSearchResults) return; - let { tokensOnLine, index } = tokenSearchResults; - - let { callTokens, parameterIndex } = utils.findCallable(tokensOnLine, index); - - if (callTokens.length === 0) return; - let paths: FinderPaths = getFinderPaths(workspaceDirectory.uri.fsPath, document.fileName); - let finder = new utils.ParsedDocFinder(parsedDoc, paths, lang.getWorkspaceDocumentText); - let resolvedResult = await finder.resolveResult(callTokens); - if (!resolvedResult.member || resolvedResult.member.memberClass !== parser.MemberClass.method) return; - if (resolvedResult) return getSignature(resolvedResult, parameterIndex, finder); - } -} - -async function getSignature(result: utils.FinderResult, parameterIndex: number, finder: utils.ParsedDocFinder): Promise { - let { code, markdown } = await lang.getDocumentation(result, finder); - - let clean = markdown.replace(/\s*(DOC)?\s*\-+/, '').replace(/\*+\s+ENDDOC/, '').trim(); - clean = clean - .split(/\r?\n/g).map(l => l.trim()).join('\n') - .replace(/(@\w+)/g, '*$1*') - .replace(/(\*(@(param|publicnew|public|throws?))\*)\s+([A-Za-z\-0-9%_\.]+)/g, '$1 `$4`'); - - let method = result.member as parser.Method; - let argString: string = method.parameters.map((param: parser.Parameter) => `${param.types[0].value} ${param.id.value}`).join(', '); - code = `${method.id.value}(${argString})`; - - let info = new vscode.SignatureInformation(code, new vscode.MarkdownString().appendMarkdown(clean)); - info.parameters = method.parameters.map(parameter => new vscode.ParameterInformation(`${parameter.types[0].value} ${parameter.id.value}`)); - - let signatureHelp = new vscode.SignatureHelp(); - signatureHelp.signatures = [info]; - signatureHelp.activeSignature = 0; - signatureHelp.activeParameter = parameterIndex; - return signatureHelp; -} diff --git a/src/language/pslSuggest.ts b/src/language/pslSuggest.ts deleted file mode 100644 index 978ff21..0000000 --- a/src/language/pslSuggest.ts +++ /dev/null @@ -1,62 +0,0 @@ -import * as path from 'path'; -import * as vscode from 'vscode'; -import { FinderPaths, getFinderPaths } from '../parser/config'; -import * as parser from '../parser/parser'; -import { MemberClass } from '../parser/parser'; -import * as utils from '../parser/utilities'; -import * as lang from './lang'; - -export class PSLCompletionItemProvider implements vscode.CompletionItemProvider { - - async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, cancellationToken: vscode.CancellationToken): Promise { - if (cancellationToken.isCancellationRequested) return; - let parsedDoc = parser.parseText(document.getText()); - - // get tokens on line and current token - let tokenSearchResults = utils.searchTokens(parsedDoc.tokens, position); - if (!tokenSearchResults) return; - let { tokensOnLine, index } = tokenSearchResults; - - const workspaceDirectory = vscode.workspace.getWorkspaceFolder(document.uri); - if (!workspaceDirectory) return; - - let callTokens = utils.getCallTokens(tokensOnLine, index); - if (callTokens.length === 0) return; - let paths: FinderPaths = getFinderPaths(workspaceDirectory.uri.fsPath, document.fileName); - let finder = new utils.ParsedDocFinder(parsedDoc, paths, lang.getWorkspaceDocumentText); - let result = await finder.resolveResult(callTokens.slice(0, -1)); - let resultFinder = result.member ? await finder.newFinder(result.member.types[0].value) : await finder.newFinder(path.basename(result.fsPath).split('.')[0]); - let resolvedResults = await resultFinder.findAllInDocument(); - if (resolvedResults) return getCompletionItems(resolvedResults, finder); - } - - async resolveCompletionItem(item: PSLCompletionItem) { - let { code, markdown } = await lang.getDocumentation(item.result, item.finder); - - let clean = markdown.replace(/\s*(DOC)?\s*\-+/, '').replace(/\*+\s+ENDDOC/, '').trim(); - clean = clean - .split(/\r?\n/g).map(l => l.trim()).join('\n') - .replace(/(@\w+)/g, '*$1*') - .replace(/(\*(@(param|publicnew|public|throws?))\*)\s+([A-Za-z\-0-9%_\.]+)/g, '$1 `$4`'); - - item.detail = code; - item.documentation = new vscode.MarkdownString().appendMarkdown(clean); - return item; - } -} - -async function getCompletionItems(results: utils.FinderResult[], finder: utils.ParsedDocFinder): Promise { - let ret = results.map(async result => { - const item = new PSLCompletionItem(result.member.id.value); - item.kind = result.member.memberClass === MemberClass.method ? vscode.CompletionItemKind.Method : vscode.CompletionItemKind.Property; - item.result = result; - item.finder = finder; - return item; - }) - return Promise.all(ret); -} - -class PSLCompletionItem extends vscode.CompletionItem { - result: utils.FinderResult; - finder: utils.ParsedDocFinder; -} diff --git a/src/mtm/hostSocket.ts b/src/mtm/hostSocket.ts deleted file mode 100644 index 5e173aa..0000000 --- a/src/mtm/hostSocket.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {Socket} from 'net'; - -export default class HostSocket { - socket: Socket; - - constructor() { - this.socket = new Socket(); - } - - // resolves when done with no value - connect(port: number, host: string): Promise { - this.onClose(); - return new Promise((resolve, reject) => { - this.socket.connect(port, host, () => { - resolve(); - }) - this.socket.once('error', (err: Error) => { - this.closeConnection(); - reject(err); - }) - }) - } - - closeConnection() { - this.socket.removeAllListeners(); - this.socket.destroy(); - } - - - onceData(): Promise { - return new Promise((resolve, reject) => { - this.socket.once('data', (ret) => { - this.socket.removeAllListeners(); - resolve(ret); - }) - this.socket.once('error', (ret) => { - this.socket.removeAllListeners(); - reject(ret.message); - }) - }) - } - - onClose(): Promise { - return new Promise(resolve => { - this.socket.once('close', (had_error) => { - resolve(had_error); - }) - }) - } - - send(messageString: string): Promise { - return new Promise(resolve => { - this.socket.write(messageString, 'ascii', () => { - resolve(); - }); - }) - } -} diff --git a/src/mtm/mtm.ts b/src/mtm/mtm.ts deleted file mode 100644 index 9c0bbf8..0000000 --- a/src/mtm/mtm.ts +++ /dev/null @@ -1,358 +0,0 @@ -import HostSocket from './hostSocket'; -import * as utils from './utils'; -import * as fs from 'fs'; - -enum ServiceClass { - CONNECTION = 0, - MRPC = 3, - SQL = 5, -} - -interface ServiceDetail { - serviceClass: ServiceClass; - mrpcID?: string; -} - -export class MtmConnection { - - private socket: HostSocket = new HostSocket() - private messageByte: string = String.fromCharCode(28); - private token: string = ''; - private messageId: number = 0; - private maxRow: number = 30; - private isSql: boolean = false; - private recordCount: number = 0; - - constructor(private serverType: string = 'SCA$IBS', private encoding: BufferEncoding = 'utf8') { } - - async open(host: string, port: number, profileUsername: string, profilePassword: string) { - await this.socket.connect(port, host); - let prepareString = utils.connectionObject(profileUsername, profilePassword); - let returnArray = await this.execute({ serviceClass: ServiceClass.CONNECTION }, prepareString); - this.token = returnArray; - } - - async send(fileName: string) { - try { - let codeToken = await this._send(fileName) - let returnString = await this.saveInProfile(fileName, codeToken) - if (returnString !== '1') { - throw new Error(returnString.split('\r\n')[1]); - } - return returnString - } - catch (err) { - this.close(); - throw new Error(err.toString()); - } - } - - async testCompile(fileName: string) { - try { - let codeToken = await this._send(fileName) - let returnString = await this._testCompile(fileName, codeToken) - return returnString - } - catch (err) { - this.close(); - throw new Error(err.toString()); - } - } - - async get(fileName: string) { - try { - let returnString = await this._get(fileName) - return returnString - } - catch (err) { - this.close(); - throw new Error(err.toString()); - } - } - - async compileAndLink(fileName: string) { - try { - let returnString = await this._compileAndLink(fileName) - return returnString - } - catch (err) { - this.close(); - throw new Error(err.toString()); - } - } - - async runPsl(fileName: string) { - try { - let codeToken = await this._send(fileName) - let returnString = await this._runPsl(codeToken) - return returnString - } - catch (err) { - this.close(); - throw new Error(err.toString()); - } - } - - async runCustom(fileName: string, mrpcID: string, request: string) { - try { - const codeToken = await this._send(fileName); - const returnString = await this._runCustom(codeToken, mrpcID, request); - return returnString; - } - catch (err) { - this.close(); - throw new Error(err.toString()); - } - } - - async close() { - this.socket.closeConnection(); - return this.socket.socket.destroyed; - } - - async batchcomp(fileName: string) { - try { - let returnString = await this.batchCompileAndLink(fileName) - return returnString - } - catch (err) { - this.close(); - throw new Error(err.toString()); - } - } - - async getTable(fileName: string) { - try { - this.isSql = false - let returnString = await this._getTable(fileName) - return returnString - } - catch (err) { - this.close(); - throw new Error(err.toString()); - } - } - - async sqlQuery(query: string) { - try { - this.isSql = true - let returnString = await this._sqlQuery(query) - return returnString - } - catch (err) { - this.close(); - throw new Error(err.toString()); - } - } - - async getPSLClasses() { - try { - let returnString = await this._getPslClasses(); - return returnString; - } - catch (err) { - this.close(); - throw new Error(err.toString()); - } - } - - private async _send(filename: string) { - let returnString: string; - let fileString: string = (await readFileAsync(filename, {encoding: this.encoding})).toString(this.encoding); - let fileContentLength: number = fileString.length; - let totalLoop: number = Math.ceil(fileContentLength / 1024); - let codeToken: string = ''; - for (let i = 0; i < totalLoop; i++) { - let partialString: string = fileString.slice(i * 1024, (i * 1024) + 1024); - let withPipe: string = ''; - for (const char of partialString) { - withPipe += char.charCodeAt(0) + '|'; - } - let prepareString: string = utils.initCodeObject(withPipe, codeToken) - returnString = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString) - codeToken = returnString; - } - let prepareString: string = utils.initCodeObject('', codeToken) - returnString = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString) - return returnString; - } - - private async saveInProfile(fileName: string, codeToken: string) { - let returnString: string; - let fileDetails = utils.getObjectType(fileName); - let prepareString = utils.saveObject(fileDetails.fileBaseName, codeToken, utils.getUserName()) - returnString = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString); - return returnString - } - - private async _testCompile(fileName: string, codeToken: string) { - let returnString: string; - let fileDetails = utils.getObjectType(fileName); - let prepareString = utils.testCompileObject(fileDetails.fileBaseName, codeToken) - returnString = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString); - return returnString - } - - private async _get(fileName: string) { - let returnString: string; - let fileDetails = utils.getObjectType(fileName); - let prepareString = utils.initObject(fileDetails.fileId, fileDetails.fileName) - returnString = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString); - let codeToken = returnString.split('\r\n')[1]; - let hasMore = '1' - returnString = '' - while (hasMore === '1') { - prepareString = utils.retObject(codeToken) - let nextReturnString = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString); - hasMore = nextReturnString.substr(0, 1); - returnString = returnString + nextReturnString.substr(1, nextReturnString.length); - } - return returnString - } - - private async _compileAndLink(fileName: string) { - let returnString: string; - let fileDetails = utils.getObjectType(fileName); - let prepareString = utils.preCompileObject(fileDetails.fileBaseName) - let codeToken = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString); - prepareString = utils.compileObject(codeToken) - returnString = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString); - return returnString; - } - - private async _runPsl(codeToken: string) { - let returnString: string; - let prepareString = utils.pslRunObject(codeToken) - returnString = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString); - return returnString; - } - - private async _runCustom(codeToken: string, mrpcID: string, request: string) { - let returnString: string; - let prepareString = utils.customRunObject(request, codeToken); - returnString = await this.execute({ mrpcID, serviceClass: ServiceClass.MRPC }, prepareString); - return returnString; - } - - // Batch complie is not working since 81 is not fully exposed from profile - private async batchCompileAndLink(fileName: string) { - let returnString: string; - let fileDetails = utils.getObjectType(fileName); - let dbtblTableName = utils.getDbtblInfo(fileDetails.fileId); - let prepareString = utils.batchCompileObject(dbtblTableName, fileDetails.fileName) - returnString = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString); - return returnString; - } - - private async _getTable(fileName: string) { - let returnString: string; - let columnList: string[]; - let fileDetails = utils.getObjectType(fileName); - let tableReturnString = fileDetails.fileBaseName + String.fromCharCode(1) + await this._get(fileName) - let selectStatement = `SELECT COUNT(DI) FROM DBTBL1D WHERE FID='${fileDetails.fileName}' `; - this.recordCount = Number(await this._sqlQuery(selectStatement)) - selectStatement = `SELECT DI FROM DBTBL1D WHERE FID='${fileDetails.fileName}'`; - returnString = await this._sqlQuery(selectStatement) - columnList = returnString.split('\r\n'); - returnString = tableReturnString - for (let i = 0; i < columnList.length; i++) { - fileName = fileDetails.fileName + '-' + columnList[i] + '.COL' - returnString = returnString + String.fromCharCode(0) + fileName + String.fromCharCode(1) + await this._get(fileName) - } - return returnString; - } - - private async _sqlQuery(selectQuery: string) { - selectQuery = selectQuery.toUpperCase() - if (!selectQuery.startsWith('SELECT')) { - throw new Error('Not a select query'); - } - let cursorNumber = new Date().getTime().toString() - let returnString = await this.openSqlCursor(cursorNumber, selectQuery) - returnString = await this.fetchSqlCursor(cursorNumber) - await this.closeSqlCursor(cursorNumber) - return returnString; - } - - private async openSqlCursor(cursorNumber: string, selectQuery: string) { - let openCursor = 'OPEN CURSOR ' + cursorNumber + ' AS '; - let rows = ''; - let prepareString = utils.sqlObject(openCursor + selectQuery, rows) - let returnString = await this.execute({ serviceClass: ServiceClass.SQL }, prepareString); - return returnString - } - - private async fetchSqlCursor(cursorNumber: string) { - let fetchCursor = 'FETCH ' + cursorNumber; - let rows = 'ROWS=' + this.maxRow; - let prepareString = utils.sqlObject(fetchCursor, rows) - let returnString = await this.execute({ serviceClass: ServiceClass.SQL }, prepareString); - let splitReturnSring: string[] = returnString.split(String.fromCharCode(0)) - let totalCount = Number(splitReturnSring[0]); - returnString = splitReturnSring[1]; - if (this.isSql === false) { - while ((totalCount < this.recordCount)) { - splitReturnSring = []; - let nextReturnString = await this.execute({ serviceClass: ServiceClass.SQL }, prepareString); - splitReturnSring = nextReturnString.split(String.fromCharCode(0)) - totalCount = totalCount + Number(splitReturnSring[0]); - returnString = returnString + '\r\n' + splitReturnSring[1] - } - } - return returnString - } - - private async closeSqlCursor(cursorNumber: string) { - let closeCursor = 'CLOSE ' + cursorNumber; - let prepareString = utils.sqlObject(closeCursor, '') - let returnString = await this.execute({ serviceClass: ServiceClass.SQL }, prepareString); - return returnString - } - - private async _getPslClasses() { - let returnString: string; - let prepareString = utils.getPslCls() - returnString = await this.execute({ mrpcID: '121', serviceClass: ServiceClass.MRPC }, prepareString); - return returnString; - } - - private async execute(detail: ServiceDetail, prepareString: string): Promise { - const sendingMessage = this.prepareSendingMessage(detail, prepareString); - await this.socket.send(sendingMessage); - let message = await this.socket.onceData(); - const { totalBytes, startByte } = utils.unpack(message); - let messageLength = message.length; - - while (messageLength < totalBytes) { - const nextMessage = await this.socket.onceData(); - messageLength = messageLength + nextMessage.length; - message = Buffer.concat([message, nextMessage], messageLength); - } - return (utils.parseResponse(detail.serviceClass, message.slice(startByte, message.length), this.encoding)); - } - - private prepareSendingMessage(detail: ServiceDetail, prepareString: string): string { - let tokenMessage = utils.tokenMessage(detail.serviceClass, this.token, this.messageId); - if (detail.serviceClass === ServiceClass.MRPC) { - let version: number = 1; - prepareString = utils.mrpcMessage(detail.mrpcID, version.toString(), prepareString) - } - let sendingMessage = utils.sendingMessage(tokenMessage, prepareString); - sendingMessage = this.serverType + this.messageByte + sendingMessage - sendingMessage = utils.pack(sendingMessage.length + 2) + sendingMessage; - this.messageId++; - return sendingMessage; - } -} - -function readFileAsync(file: string, options?: {encoding?: string, flag?: string}): Promise { - return new Promise((resolve, reject) => { - fs.readFile(file, {encoding: null, flag: options.flag}, (err, data) => { - if (err) { - reject(err); - } else { - resolve(data); - } - }); - }); -} diff --git a/src/mtm/utils.ts b/src/mtm/utils.ts deleted file mode 100644 index 413ed33..0000000 --- a/src/mtm/utils.ts +++ /dev/null @@ -1,346 +0,0 @@ -import * as os from 'os'; -import * as path from 'path'; - -interface FileDetails { - fileId: string - fileName: string - fileBaseName: string -} - -export const extensionToDescription: { [key: string]: string } = { - 'BATCH': 'Batch', - 'COL': 'Column', - 'DAT': 'Data', - 'FKY': 'Foreign Key', - // 'G': 'Global', - 'IDX': 'Index', - 'JFD': 'Journal', - 'm': 'M routine', - 'PPL': 'Pre Post Lib', - 'PROC': 'Procedure', - 'properties': 'properties file', - 'PSL': 'psl File', - 'psl': 'psl File', - 'pslx': 'pslx File', - 'pslxtra': 'pslxtra File', - 'psql': 'PSQLScript', - 'serial': 'Serialized Data', - 'QRY': 'Query', - 'RPT': 'Report', - 'SCR': 'Screen', - // TABLE not supported - // 'TABLE': 'Complete Table', - 'TBL': 'Table', - 'TRIG': 'Trigger', -} - -export function v2lvFormat(messageValue: string[]) { - let lvMessage = '' - if (messageValue.length !== 0) { - messageValue.forEach(messageString => { - lvMessage = lvMessage + lvFormat(messageString) - }) - } - return lvMessage -} - -export function lvFormat(messagString: String): string { - let returnLvFormat = '' - let lvArray = [] - let messageLength = messagString.length - let splitBytes - - if (messageLength < 255) { splitBytes = 1 } - else if (messageLength < 65534) { splitBytes = 2 } - else if (messageLength < 16777213) { splitBytes = 3 } - else { splitBytes = 4 } - - messageLength = splitBytes + messageLength - - if (messageLength > 255) { - for (let loop = 0; loop < splitBytes; loop++) { - lvArray.push(messageLength % 256) - messageLength = Math.trunc(messageLength / 256) - } - returnLvFormat = String.fromCharCode(0) + String.fromCharCode(splitBytes); - for (let loop = splitBytes - 1; loop >= 0; loop--) { - returnLvFormat = returnLvFormat + String.fromCharCode(lvArray[loop]) - } - } - else { returnLvFormat = String.fromCharCode(messageLength) } - return (returnLvFormat + messagString); -} - -/** - * This method does a thing. - * - * @export - * @param {Buffer} messageString The message string - * @returns {Buffer[]} A buffer array - */ -export function lv2vFormat(messageString: Buffer): Buffer[] { - let returnString: Buffer[] = []; - let messageLength = messageString.length; - - if (messageLength === 0) { return [] }; - - let bytePointer: number = 0; - let extractChar: number = 0; - let numberOfBufferedLine: number = 0; - let byteCalcNumber: number; - - while (bytePointer < messageLength) { - extractChar = messageString.readUInt8(bytePointer); - - numberOfBufferedLine = 1; - - if (extractChar === 0) { - numberOfBufferedLine = messageString.readUInt8(bytePointer + 1); - bytePointer = bytePointer + 2; - if (numberOfBufferedLine === 0) { - continue; - } - byteCalcNumber = 1; - for (let loopFor = numberOfBufferedLine - 1; loopFor >= 0; loopFor--) { - extractChar = (messageString.readUInt8(bytePointer + loopFor) * byteCalcNumber) + extractChar; - byteCalcNumber = byteCalcNumber * 256 - } - } - if (bytePointer > messageLength) { - continue; - } - returnString.push(messageString.slice(bytePointer + numberOfBufferedLine, bytePointer + extractChar)); - bytePointer = bytePointer + extractChar; - } - return returnString -} - -export function parseResponse(serviceClass: number, outputData: Buffer, encoding: BufferEncoding): string { - // unpacking multiple times to get the token, remove the endiness by extracting from position 2 - let returnString: string = '' - let returnArray: Buffer[]; - returnArray = lv2vFormat(outputData); - returnArray = lv2vFormat(returnArray[1]); - returnArray = lv2vFormat(returnArray[1]); - returnString = returnArray[0].toString(encoding) - if (returnString === 'ER') { - throw returnArray.map(x => x.toString(encoding)).join('') - } - if (serviceClass === 5) { - returnString = returnArray[2].toString(encoding) + String.fromCharCode(0) + returnArray[3].toString(encoding) - } - return returnString; -} - -export function sendingMessage(tokenMessage: string, mrpcMessage: string): string { - return v2lvFormat([tokenMessage, mrpcMessage]) -} - -export function mrpcMessage(mrpcId: string, version: string, prepareString: string): string { - let exchangeMessage = [ - mrpcId, - version, - prepareString, - mrpcConnMessage() - ]; - return v2lvFormat(exchangeMessage); -} - - -export function tokenMessage(serviceClass: number, token: string, messageId: number): string { - let exchangeMessage = [ - serviceClass.toString(), - token, - messageId.toString(), - '0', - '' - ] - return v2lvFormat(exchangeMessage); -} - - -export function connectionObject(envUser: string, envPassword: string): string { - let perpareString: string[] = [ - '1', - envUser.toString(), - 'nowhere', - envPassword, - '', - '', - netConnMessage() - ] - return v2lvFormat(perpareString); -} - -export function checkObject(localFile: string, token: string): string { - let messageArray = [ - 'CHECKOBJ', - '', '', localFile, '', '', token - ]; - return v2lvFormat(messageArray); -} - -export function saveObject(localFile: string, token: string, username: string): string { - let messageArray = [ - 'SAVEOBJ', - '', '', localFile, '', '', token, username - ]; - return v2lvFormat(messageArray); -} - -export function initCodeObject(code: string, compilationToken: string): string { - let messageArray = [ - 'INITCODE', - code, compilationToken - ]; - return v2lvFormat(messageArray); -} - -export function testCompileObject(fileName: string, compilationToken: string): string { - let messageArray = [ - 'EXECCOMP', - '', compilationToken, fileName - ]; - return v2lvFormat(messageArray); -} - -export function initObject(objectId: string, objectName: string): string { - let messageArray = [ - 'INITOBJ', - '', '', '', objectId, objectName - ]; - return v2lvFormat(messageArray); -} - -export function retObject(token: string): string { - let messageArray = [ - 'RETOBJ', - '', '', '', '', '', token - ]; - return v2lvFormat(messageArray); -} - -export function preCompileObject(fileName: string): string { - let messageArray = [ - 'PRECMP', - '', '', fileName - ]; - return v2lvFormat(messageArray); -} - -export function compileObject(compilationToken: string): string { - let messageArray = [ - 'CMPLINK', - '', compilationToken - ] - return v2lvFormat(messageArray); -} - -export function pslRunObject(compilationToken: string): string { - let messageArray = [ - 'PSLRUN', - '', compilationToken - ]; - return v2lvFormat(messageArray); -} - -export function customRunObject(request: string, compilationToken: string): string { - let messageArray = [ - request, - '', compilationToken - ]; - return v2lvFormat(messageArray); -} - -export function sqlObject(query: string, rows: string) { - let messageArray = [ - query, - rows, - '' - ] - return v2lvFormat(messageArray); -} - -export function batchCompileObject(dbtblTableName: string, elementName: string): string { - let messageArray = [ - dbtblTableName, - elementName - ] - return v2lvFormat(messageArray); -} - -export function getPslCls(): string { - let messageArray = [ - 'GETPSLCLS', '', '' - ]; - return v2lvFormat(messageArray); -} - -export function getUserName(): string { - return os.userInfo().username; -} - -export function getObjectType(fileName: string): FileDetails { - let elementBaseName: string = path.basename(fileName) - let elementName = elementBaseName.substr(0, elementBaseName.lastIndexOf('.')) - let elementExtension = elementBaseName.substr(elementBaseName.lastIndexOf('.') + 1, elementBaseName.length) - if (elementName.includes('.')) elementName = elementBaseName; - return { - fileId: getFileDetails(elementExtension), - fileName: elementName, - fileBaseName: elementBaseName - } -} - -function getFileDetails(fileExtension: string) { - if (fileExtension in extensionToDescription) return extensionToDescription[fileExtension]; - throw new Error(`Invalid file extension: ${fileExtension}`); - -} - -export function getDbtblInfo(fileId: string): string { - switch (fileId) { - case 'Batch': return 'DBTBL33'; - case 'Column': return 'DBTBL25'; - case 'Procedure': return 'DBTBL1'; - case 'Table': return 'DBTBL1'; - default: return 'Unknown Type'; - } -} - -export function pack(totalLength: number): string { - // For ING we use Big Endian !h which is 2 bytes - let quotient = Math.floor(totalLength / 256); - let firstByte = String.fromCharCode(quotient); - let secondByte = String.fromCharCode(totalLength - (quotient * 256)); - return (firstByte + secondByte); -} - -export function unpack(message: Buffer): { totalBytes: number, startByte: number } { - // For ING we use Big Endian !h which is 2 bytes - if (!message.readUInt8(0) && !message.readUInt8(1)) return longMessageLength(message); - return { totalBytes: (message.readUInt8(0) * 256) + message.readUInt8(1), startByte: 3 }; -} - -function longMessageLength(message: Buffer): { totalBytes: number, startByte: number } { - // the third byte of the message tells us how many bytes are used to encode the length - const numberOfBytes = message.readUInt8(2); - const lastLengthByte = 3 + numberOfBytes; - - // slice the message to just use the bytes that encode message length - const messageLengthBytes = message.slice(3, lastLengthByte); - let totalBytes = 0; - for (let index = 0; index < messageLengthBytes.length; index++) { - const byte = messageLengthBytes.readUInt8(index); - totalBytes += byte * 256 ** (messageLengthBytes.length - 1 - index); - } - return { totalBytes, startByte: lastLengthByte + 1}; -} - -function mrpcConnMessage(): string { - return String.fromCharCode(4, 3, 2) + '1'; -} - -function netConnMessage(): string { - return String.fromCharCode(21, 2) + '5' + String.fromCharCode(6) + 'ICODE' + String.fromCharCode(2) + '1' + String.fromCharCode(8) + 'PREPARE' + String.fromCharCode(2) + '3'; -} diff --git a/src/parser/.npmrc.psl-parser b/src/parser/.npmrc.psl-parser deleted file mode 100644 index bbd9e9e..0000000 --- a/src/parser/.npmrc.psl-parser +++ /dev/null @@ -1,4 +0,0 @@ -always-auth=true -registry=https://registry.npmjs.org -//registry.npmjs.org/:_authToken=${PARSER_TOKEN} -//registry.npmjs.org/:username=${PARSER_USER} diff --git a/src/parser/README.md b/src/parser/README.md deleted file mode 100644 index 100e58c..0000000 --- a/src/parser/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# psl-parser - -TypeScript implementation of a PSL parser, from scratch. - -## Usage - -```javascript -import { parseText } from 'psl-parser'; - -const parsedPsl = parseText(/* PSL source text */); - -parsedPsl.methods.forEach(method => { - console.log(method.id.value); -}) -``` diff --git a/src/parser/package.json b/src/parser/package.json deleted file mode 100644 index 707bf8a..0000000 --- a/src/parser/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "psl-parser", - "version": "0.0.3", - "description": "A parser for the Profile Scripting Language", - "main": "out/index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/ing-bank/vscode-psl.git" - }, - "author": "atiplea", - "license": "MIT", - "bugs": { - "url": "https://github.com/ing-bank/vscode-psl/issues" - }, - "homepage": "https://github.com/ing-bank/vscode-psl#readme", - "dependencies": { - "fs-extra": "^5.0.0" - } -} diff --git a/src/parser/tsconfig.json b/src/parser/tsconfig.json deleted file mode 100644 index c047352..0000000 --- a/src/parser/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es2017", - "lib": [ - "es2017" - ], - "outDir": "out", - "declaration": true, - "sourceMap": true, - "rootDir": "." - }, - "formatCodeOptions": { - "newLine": "LF" - }, - "exclude": [ - "node_modules", - "out" - ] -} diff --git a/src/pslLint/activate.ts b/src/pslLint/activate.ts deleted file mode 100644 index 5fc40fa..0000000 --- a/src/pslLint/activate.ts +++ /dev/null @@ -1,156 +0,0 @@ -import * as path from 'path'; -import { - DeclarationRule, Diagnostic, FileDefinitionRule, MemberRule, MethodRule, ParameterRule, - ProfileComponent, ProfileComponentRule, PropertyRule, PslRule, -} from './api'; -import { getConfig, matchConfig } from './config'; - -/** - * Import rules here. - */ -import { ParsedDocument } from '../parser/parser'; -import { - MemberCamelCase, MemberLength, MemberLiteralCase, - MemberStartsWithV, PropertyIsDummy, PropertyIsDuplicate, -} from './elementsConventionChecker'; -import { MethodDocumentation, MethodSeparator, TwoEmptyLines } from './methodDoc'; -import { MultiLineDeclare } from './multiLineDeclare'; -import { MethodParametersOnNewLine } from './parameters'; -import { RuntimeStart } from './runtime'; -import { TblColDocumentation } from './tblcolDoc'; -import { TodoInfo } from './todos'; - -/** - * Add new rules here to have them checked at the appropriate time. - */ -const componentRules: ProfileComponentRule[] = []; -const fileDefinitionRules: FileDefinitionRule[] = [ - new TblColDocumentation(), -]; -const pslRules: PslRule[] = [ - new TodoInfo(), -]; -const memberRules: MemberRule[] = [ - new MemberCamelCase(), - new MemberLength(), - new MemberStartsWithV(), - new MemberLiteralCase(), -]; -const methodRules: MethodRule[] = [ - new MethodDocumentation(), - new MethodSeparator(), - new MethodParametersOnNewLine(), - new RuntimeStart(), - new MultiLineDeclare(), - new TwoEmptyLines(), -]; -const propertyRules: PropertyRule[] = [ - new PropertyIsDummy(), - new PropertyIsDuplicate(), -]; -const declarationRules: DeclarationRule[] = []; -const parameterRules: ParameterRule[] = []; - -export function getDiagnostics( - profileComponent: ProfileComponent, - parsedDocument?: ParsedDocument, - useConfig?: boolean, -): Diagnostic[] { - const subscription = new RuleSubscription(profileComponent, parsedDocument, useConfig); - return subscription.reportRules(); -} - -/** - * Interface for adding and executing rules. - */ -class RuleSubscription { - - private diagnostics: Diagnostic[]; - private componentRules: ProfileComponentRule[]; - private pslRules: PslRule[]; - private fileDefinitionRules: FileDefinitionRule[]; - private methodRules: MethodRule[]; - private memberRules: MemberRule[]; - private propertyRules: PropertyRule[]; - private declarationRules: DeclarationRule[]; - private parameterRules: ParameterRule[]; - - constructor(private profileComponent: ProfileComponent, private parsedDocument?: ParsedDocument, useConfig?: boolean) { - this.diagnostics = []; - - const config = useConfig ? getConfig(this.profileComponent.fsPath) : undefined; - - const initializeRules = (rules: ProfileComponentRule[]) => { - return rules.filter(rule => { - if (!config) return true; - return matchConfig(path.basename(this.profileComponent.fsPath), rule.ruleName, config); - }).map(rule => { - rule.profileComponent = this.profileComponent; - return rule; - }); - }; - const initializePslRules = (rules: PslRule[]) => { - const componentInitialized = initializeRules(rules) as PslRule[]; - const pslParsedDocument = this.parsedDocument as ParsedDocument; - return componentInitialized.map(rule => { - rule.parsedDocument = pslParsedDocument; - return rule; - }); - }; - - this.componentRules = initializeRules(componentRules); - this.fileDefinitionRules = initializeRules(fileDefinitionRules); - this.pslRules = initializePslRules(pslRules); - this.methodRules = initializePslRules(methodRules); - this.memberRules = initializePslRules(memberRules); - this.propertyRules = initializePslRules(propertyRules); - this.declarationRules = initializePslRules(declarationRules); - this.parameterRules = initializePslRules(parameterRules); - } - - reportRules(): Diagnostic[] { - const addDiagnostics = (rules: ProfileComponentRule[], ...args: any[]) => { - rules.forEach(rule => this.diagnostics.push(...rule.report(...args))); - }; - - addDiagnostics(this.componentRules); - - if (ProfileComponent.isFileDefinition(this.profileComponent.fsPath)) { - addDiagnostics(this.fileDefinitionRules); - } - - if (ProfileComponent.isPsl(this.profileComponent.fsPath)) { - addDiagnostics(this.pslRules); - - const parsedDocument = this.parsedDocument as ParsedDocument; - - for (const property of parsedDocument.properties) { - addDiagnostics(this.memberRules, property); - addDiagnostics(this.propertyRules, property); - } - - for (const declaration of parsedDocument.declarations) { - addDiagnostics(this.memberRules, declaration); - addDiagnostics(this.declarationRules, declaration); - } - - for (const method of parsedDocument.methods) { - addDiagnostics(this.memberRules, method); - addDiagnostics(this.methodRules, method); - - for (const parameter of method.parameters) { - addDiagnostics(this.memberRules, parameter); - addDiagnostics(this.parameterRules, parameter, method); - } - - for (const declaration of method.declarations) { - addDiagnostics(this.memberRules, declaration); - addDiagnostics(this.declarationRules, declaration, method); - } - } - - } - - return this.diagnostics; - } -} diff --git a/src/pslLint/api.ts b/src/pslLint/api.ts deleted file mode 100644 index fcbae73..0000000 --- a/src/pslLint/api.ts +++ /dev/null @@ -1,230 +0,0 @@ -import * as path from 'path'; -import { Declaration, Member, Method, Parameter, ParsedDocument, Property } from './../parser/parser'; -import { Position, Range } from './../parser/tokenizer'; - -export enum DiagnosticSeverity { - - /** - * Something not allowed by the rules of a language or other means. - */ - Error = 0, - - /** - * Something suspicious but allowed. - */ - Warning = 1, - - /** - * Something to inform about but not a problem. - */ - Information = 2, - - /** - * Something to hint to a better way of doing it, like proposing - * a refactoring. - */ - Hint = 3, -} - -export class Diagnostic { - - /** - * The range to which this diagnostic applies. - */ - range: Range; - - /** - * The human-readable message. - */ - message: string; - - /** - * A human-readable string describing the source of this - * diagnostic, e.g. 'typescript' or 'super lint'. - */ - source?: string; - - /** - * The severity, default is [error](#DiagnosticSeverity.Error). - */ - severity?: DiagnosticSeverity; - - /** - * A code or identifier for this diagnostics. Will not be surfaced - * to the user, but should be used for later processing, e.g. when - * providing [code actions](#CodeActionContext). - */ - code?: string | number; - - ruleName: string; - - /** - * An array of related diagnostic information, e.g. when symbol-names within - * a scope collide all definitions can be marked via this property. - */ - relatedInformation?: DiagnosticRelatedInformation[]; - - member?: Member; - - /** - * Creates a new diagnostic object. - * - * @param range The range to which this diagnostic applies. - * @param message The human-readable message. - * @param severity The severity, default is [error](#DiagnosticSeverity.Error). - */ - constructor(range: Range, message: string, ruleName: string, severity?: DiagnosticSeverity, member?: Member) { - this.range = range; - this.message = message; - this.ruleName = ruleName; - if (severity) this.severity = severity; - if (member) this.member = member; - } -} - -/** - * Represents a related message and source code location for a diagnostic. This should be - * used to point to code locations that cause or related to a diagnostics, e.g when duplicating - * a symbol in a scope. - */ -export class DiagnosticRelatedInformation { - - /** - * The range of this related diagnostic information. - */ - range: Range; - - /** - * The message of this related diagnostic information. - */ - message: string; - - /** - * Creates a new related diagnostic information object. - * - * @param range The range. - * @param message The message. - */ - constructor(range: Range, message: string) { - this.range = range; - this.message = message; - } -} - -export abstract class ProfileComponentRule { - - readonly ruleName: string = this.constructor.name; - - profileComponent: ProfileComponent; - - abstract report(...args: any[]): Diagnostic[]; -} - -export abstract class FileDefinitionRule extends ProfileComponentRule { } - -export abstract class PslRule extends ProfileComponentRule { - - parsedDocument: ParsedDocument; - - abstract report(...args: any[]): Diagnostic[]; -} - -export abstract class MemberRule extends PslRule { - abstract report(member: Member): Diagnostic[]; -} - -export abstract class PropertyRule extends PslRule { - abstract report(property: Property): Diagnostic[]; -} - -export abstract class MethodRule extends PslRule { - abstract report(method: Method): Diagnostic[]; -} - -export abstract class ParameterRule extends PslRule { - abstract report(parameter: Parameter, method: Method): Diagnostic[]; -} - -export abstract class DeclarationRule extends PslRule { - abstract report(declaration: Declaration, method?: Method): Diagnostic[]; -} - -type GetTextMethod = (lineNumber: number) => string; - -/** - * A ProfileComponent contains information about a file used in Profile. - * The file may be PSL or non-PSL (such as a TBL or COL). - */ -export class ProfileComponent { - - static isPsl(fsPath: string): boolean { - return path.extname(fsPath) === '.PROC' - || path.extname(fsPath) === '.BATCH' - || path.extname(fsPath) === '.TRIG' - || path.extname(fsPath).toUpperCase() === '.PSL'; - } - - static isFileDefinition(fsPath: string): boolean { - return path.extname(fsPath) === '.TBL' - || path.extname(fsPath) === '.COL'; - } - - static isProfileComponent(fsPath: string): boolean { - return ProfileComponent.isPsl(fsPath) - || ProfileComponent.isFileDefinition(fsPath); - } - - fsPath: string; - textDocument: string; - - private indexedDocument?: Map; - - constructor(fsPath: string, textDocument: string, getTextAtLine?: GetTextMethod) { - this.textDocument = textDocument; - this.fsPath = fsPath; - if (getTextAtLine) this.getTextAtLine = getTextAtLine; - } - - /** - * A utility method to get the text at a specified line of the document. - * @param lineNumber The zero-based line number of the document where the text is. - */ - getTextAtLine(lineNumber: number): string { - if (lineNumber < 0) { - throw new Error('Cannot get text at negative line number.'); - } - if (!this.indexedDocument) { - this.indexedDocument = this.createIndexedDocument(); - } - return this.indexedDocument.get(lineNumber) || ''; - } - - /** - * Converts a zero-based offset to a position. - * - * @param offset A zero-based offset. - * @return A valid [position](#Position). - */ - positionAt(offset: number): Position { - const before = this.textDocument.slice(0, offset); - const newLines = before.match(/\n/g); - const line = newLines ? newLines.length : 0; - const preCharacters = before.match(/(\n|^).*$/g); - return new Position(line, preCharacters ? preCharacters[0].length : 0); - } - - private createIndexedDocument(): Map { - const indexedDocument = new Map(); - let line: string = ''; - let index: number = 0; - for (const char of this.textDocument) { - line += char; - if (char === '\n') { - indexedDocument.set(index, line); - index++; - line = ''; - } - } - return indexedDocument; - } -} diff --git a/src/pslLint/cli/.npmignore b/src/pslLint/cli/.npmignore deleted file mode 100644 index b03f0d1..0000000 --- a/src/pslLint/cli/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -*.ts -!*.d.ts -tsconfig.json -*.tgz -.npmrc* -*.map diff --git a/src/pslLint/cli/.npmrc.psl-lint b/src/pslLint/cli/.npmrc.psl-lint deleted file mode 100644 index 420399d..0000000 --- a/src/pslLint/cli/.npmrc.psl-lint +++ /dev/null @@ -1,4 +0,0 @@ -always-auth=true -registry=https://registry.npmjs.org -//registry.npmjs.org/:_authToken=${LINT_TOKEN} -//registry.npmjs.org/:username=${LINT_USER} diff --git a/src/pslLint/cli/README.md b/src/pslLint/cli/README.md deleted file mode 100644 index eae911f..0000000 --- a/src/pslLint/cli/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# psl-lint - -A linter or lint refers to tools that analyze source code to flag programming errors, bugs, stylistic errors, and suspicious constructs. - -This module works by adding rules that are automatically checked at the appropriate time. - -## Current Rules - -* MemberCamelCase -* MemberLength -* MemberLiteralCase -* MemberStartsWithV -* MethodDocumentation -* MethodParametersOnNewLine -* MethodSeparator -* MultiLineDeclare -* PropertyIsDummy -* PropertyIsDuplicate -* RuntimeStart -* TblColDocumentation -* TodoInfo -* TwoEmptyLines - - -## Contributing - -To add a rule, create a class implementing one of the rule interfaces. Then, add an instance of your class to the `addRules` method found in the `activate.ts` module. - -Rules will have a parsed document at their disposal. Auto-complete can guide you to using the parsed document effectively. Use the `todo.ts` and `parameters.ts` modules as examples. - -Tests can be found in the `__tests__` directory at the root of the vscode-psl project. Use `parameters-test.ts` as an example. - -## TODO - -* More tests -* Build/Deploy/Integrate diff --git a/src/pslLint/cli/cli.ts b/src/pslLint/cli/cli.ts deleted file mode 100644 index d8aadc2..0000000 --- a/src/pslLint/cli/cli.ts +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env node -import { Command } from 'commander'; -import * as crypto from 'crypto'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import * as process from 'process'; -import { parseText } from '../../parser/parser'; -import { getDiagnostics } from '../activate'; -import { Diagnostic, DiagnosticSeverity, ProfileComponent } from '../api'; -import { setConfig } from '../config'; - -interface CodeClimateIssue { - categories?: string[]; - check_name: string; - description: string; - location: CodeClimateLocation; - fingerprint: string; -} - -interface CodeClimateLocation { - path: string; - lines: CodeClimateLines; -} - -interface CodeClimateLines { - begin: number; - end: number; -} - -interface StoredDiagnostic { - diagnostic: Diagnostic; - fsPath: string; -} - -const diagnosticStore: Map = new Map(); -let useConfig: boolean; - -function getMessage(storedDiagnostic: StoredDiagnostic) { - const { diagnostic, fsPath } = storedDiagnostic; - const range = `${diagnostic.range.start.line + 1},${diagnostic.range.start.character + 1}`; - const severity = `${DiagnosticSeverity[diagnostic.severity].substr(0, 4).toUpperCase()}`; - return `${fsPath}(${range}) [${severity}][${diagnostic.source}][${diagnostic.ruleName}] ${diagnostic.message}`; -} - -async function readFile(filename: string): Promise { - let errorCount = 0; - const fsPath = path.relative(process.cwd(), filename); - if (!ProfileComponent.isProfileComponent(fsPath)) { - return errorCount; - } - const textDocument = (await fs.readFile(fsPath)).toString(); - const parsedDocument = ProfileComponent.isPsl(fsPath) ? parseText(textDocument) : undefined; - const profileComponent = new ProfileComponent(fsPath, textDocument); - - const diagnostics = getDiagnostics(profileComponent, parsedDocument, useConfig); - - diagnostics.forEach(diagnostic => { - if (diagnostic.severity === DiagnosticSeverity.Warning || diagnostic.severity === DiagnosticSeverity.Error) { - errorCount += 1; - } - const mapDiagnostics = diagnosticStore.get(diagnostic.source); - if (!mapDiagnostics) diagnosticStore.set(diagnostic.source, [{ diagnostic, fsPath }]); - else mapDiagnostics.push({ diagnostic, fsPath }); - }); - - return errorCount; -} - -export async function readPath(fileString: string) { - const files = fileString.split(';').filter(x => x); - const promises: Array> = []; - let exitCode = 0; - for (const filePath of files) { - const absolutePath = path.resolve(filePath); - if (!absolutePath) continue; - const stat = await fs.lstat(absolutePath); - if (stat.isDirectory()) { - const fileNames = await fs.readdir(absolutePath); - for (const fileName of fileNames) { - const absolutePathInDir = path.resolve(path.join(absolutePath, fileName)); - await readPath(absolutePathInDir); - } - } - else if (stat.isFile()) { - const promise = readFile(absolutePath).then(errorCount => { - exitCode += errorCount; - }).catch((e: Error) => { - if (e.message) console.error(absolutePath, e.message, e.stack); - else console.error(absolutePath, e); - }); - promises.push(promise); - } - } - await Promise.all(promises); - return exitCode; -} - -async function processConfig(): Promise { - const configPath = path.join(process.cwd(), 'psl-lint.json'); - await fs.lstat(configPath).then(async () => { - await setConfig(configPath); - useConfig = true; - }).catch(() => { - useConfig = false; - }); -} - -async function outputResults(reportFileName?: string) { - if (reportFileName) { - await generateCodeQualityReport(reportFileName); - console.log('Finished report.'); - } - else { - printOutputToConsole(); - console.log('Finished lint.'); - } -} - -function printOutputToConsole() { - for (const source of diagnosticStore.keys()) { - const diagnostics = diagnosticStore.get(source); - const word = diagnosticStore.get(source).length === 1 ? 'diagnostic' : 'diagnostics'; - console.log(`[${source}] ${diagnostics.length} ${word}:`); - diagnostics.forEach(diagnostic => { - console.log(getMessage(diagnostic)); - }); - } -} - -async function generateCodeQualityReport(reportFileName: string) { - const counts: { - [ruleName: string]: number; - } = {}; - const issues: CodeClimateIssue[] = []; - for (const ruleDiagnostics of diagnosticStore.values()) { - for (const storedDiagnostic of ruleDiagnostics) { - const { diagnostic, fsPath } = storedDiagnostic; - const count = counts[diagnostic.ruleName]; - if (!count) { - counts[diagnostic.ruleName] = 1; - } - else { - counts[diagnostic.ruleName] = counts[diagnostic.ruleName] + 1; - } - if (diagnostic.ruleName === 'MemberCamelCase') continue; - const issue: CodeClimateIssue = { - check_name: diagnostic.ruleName, - description: `[${diagnostic.ruleName}] ${diagnostic.message.trim().replace(/\.$/, '')}`, - fingerprint: hashObject(diagnostic), - location: { - lines: { - begin: diagnostic.range.start.line + 1, - end: diagnostic.range.end.line + 1, - }, - path: fsPath, - }, - }; - issues.push(issue); - } - } - console.log('Diagnostics found in repository:'); - (console as any).table(counts); - await fs.writeFile(reportFileName, JSON.stringify(issues)); -} - -function hashObject(object: any) { - const hash = crypto.createHash('md5') - .update(JSON.stringify(object, (key, value) => { - if (key[0] === '_') return undefined; // remove api stuff - else if (typeof value === 'function') { // consider functions - return value.toString(); - } - else return value; - })) - .digest('hex'); - return hash; -} - -function getCliArgs() { - const command = new Command('psl-lint'); - command - .argument('') - .name('psl-lint') - .usage('') - .option('-o, --output ', 'Name of output file') - .description('fileString a ; delimited string of file paths') - .parse(process.argv); - return { fileString: command.args[0], reportFileName: command.getOptionValue('output') }; - } - -(async function main() { - if (require.main !== module) { - return; - } - const { fileString, reportFileName } = getCliArgs(); - if (fileString) { - - await processConfig(); - - if (reportFileName) console.log('Starting report.'); - else console.log('Starting lint.'); - - const exitCode = await readPath(fileString); - await outputResults(reportFileName); - process.exit(exitCode); - } - else { - console.log('Nothing to lint.'); - } -})(); - -// psl-lint $(git diff master...${CI_BUILD_REF_NAME} --name-only | tr "\n" ";") diff --git a/src/pslLint/cli/package-lock.json b/src/pslLint/cli/package-lock.json deleted file mode 100644 index d145120..0000000 --- a/src/pslLint/cli/package-lock.json +++ /dev/null @@ -1,162 +0,0 @@ -{ - "name": "psl-lint", - "version": "1.6.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "psl-lint", - "version": "1.6.0", - "license": "MIT", - "dependencies": { - "commander": "^9.4.1", - "fs-extra": "^10.1.0", - "minimatch": "^5.1.0" - }, - "bin": { - "psl-lint": "lib/pslLint/cli/cli.js" - }, - "devDependencies": { - "@types/node": "^18.11.4" - } - }, - "node_modules/@types/node": { - "version": "18.11.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.4.tgz", - "integrity": "sha512-BxcJpBu8D3kv/GZkx/gSMz6VnTJREBj/4lbzYOQueUOELkt8WrO6zAcSPmp9uRPEW/d+lUO8QK0W2xnS1hEU0A==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/commander": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", - "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", - "engines": { - "node": "^12.20.0 || >=14" - } - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "engines": { - "node": ">= 10.0.0" - } - } - }, - "dependencies": { - "@types/node": { - "version": "18.11.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.4.tgz", - "integrity": "sha512-BxcJpBu8D3kv/GZkx/gSMz6VnTJREBj/4lbzYOQueUOELkt8WrO6zAcSPmp9uRPEW/d+lUO8QK0W2xnS1hEU0A==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "requires": { - "balanced-match": "^1.0.0" - } - }, - "commander": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", - "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==" - }, - "fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - } - } -} diff --git a/src/pslLint/cli/package.json b/src/pslLint/cli/package.json deleted file mode 100644 index 67a517d..0000000 --- a/src/pslLint/cli/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "psl-lint", - "version": "1.6.0", - "description": "Code quality for PSL", - "main": "./lib/pslLint/cli/cli.js", - "bin": { - "psl-lint": "./lib/pslLint/cli/cli.js" - }, - "repository": { - "type": "git", - "url": "https://github.com/ing-bank/vscode-psl" - }, - "keywords": [], - "author": "atiplea", - "license": "MIT", - "dependencies": { - "commander": "^9.4.1", - "fs-extra": "^10.1.0", - "minimatch": "^5.1.0" - }, - "devDependencies": { - "@types/node": "^18.11.4" - } -} diff --git a/src/pslLint/cli/tsconfig.json b/src/pslLint/cli/tsconfig.json deleted file mode 100644 index b127abe..0000000 --- a/src/pslLint/cli/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es2017", - "lib": [ - "es2017" - ], - "outDir": "lib", - "sourceMap": true, - "declaration": true, - "rootDir": "./../.." - }, - "formatCodeOptions": { - "newLine": "LF" - }, - "exclude": [ - "node_modules", - "lib" - ] -} diff --git a/src/pslLint/config.ts b/src/pslLint/config.ts deleted file mode 100644 index 1ea664d..0000000 --- a/src/pslLint/config.ts +++ /dev/null @@ -1,83 +0,0 @@ -import * as fs from 'fs-extra'; -import * as minimatch from 'minimatch'; -import * as path from 'path'; - -type ConfigBaseDir = string; -export let activeConfigs: Map = new Map(); - -export interface Config { - include: ConfigSetting; - exclude: ConfigSetting; -} -export interface RegexConfig { - include: RegexConfigObj[]; - exclude: RegexConfigObj[]; -} -interface ConfigSetting { [filePattern: string]: string[]; } - -interface RegexConfigObj { - pattern: RegExp; - rules: string[]; -} - -export async function setConfig(configPath: string) { - const configBaseDir: ConfigBaseDir = path.dirname(configPath); - const config: Config = await fs.readFile(configPath).then(b => JSON.parse(b.toString())); - activeConfigs.set(configBaseDir, transform(config)); -} - -export function transform(config: Config): RegexConfig { - const includes: RegexConfigObj[] = []; - const excludes: RegexConfigObj[] = []; - for (const pattern in config.include) { - if (config.include.hasOwnProperty(pattern)) { - const rules = config.include[pattern]; - const regexpPattern = minimatch.makeRe(pattern) - - if (!regexpPattern) throw new Error(`Invalid regexp patter ${pattern}`); - - includes.push({ pattern: regexpPattern, rules }); - } - } - for (const pattern in config.exclude) { - if (config.exclude.hasOwnProperty(pattern)) { - const rules = config.exclude[pattern]; - const regexpPattern = minimatch.makeRe(pattern) - - if (!regexpPattern) throw new Error(`Invalid regexp patter ${pattern}`); - - excludes.push({ pattern: regexpPattern, rules }); - } - } - return { include: includes, exclude: excludes }; -} - -export async function removeConfig(configPath: string) { - const configBaseDir: ConfigBaseDir = path.dirname(configPath); - activeConfigs.delete(configBaseDir); -} - -export function getConfig(fsPath: string): RegexConfig | undefined { - for (const configBaseDir of activeConfigs.keys()) { - const relative = path.relative(configBaseDir, fsPath); - if (!!relative && !relative.startsWith('..') && !path.isAbsolute(relative)) { - return activeConfigs.get(configBaseDir); - } - } -} - -export function matchConfig(fileName: string, ruleName: string, configObj: RegexConfig) { - let matches: boolean = false; - const findMatch = (configSettings: RegexConfigObj[]) => { - for (const configSetting of configSettings) { - if (!fileName.match(configSetting.pattern)) continue; - for (const rulePattern of configSetting.rules) { - if (rulePattern === '*' || rulePattern === ruleName) return true; - } - } - }; - - matches = findMatch(configObj.include) || false; - if (!matches) return false; - return !findMatch(configObj.exclude); -} diff --git a/src/pslLint/elementsConventionChecker.ts b/src/pslLint/elementsConventionChecker.ts deleted file mode 100644 index a8c0a59..0000000 --- a/src/pslLint/elementsConventionChecker.ts +++ /dev/null @@ -1,259 +0,0 @@ -import { Member, MemberClass, Method, Property } from '../parser/parser'; -import { - Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, MemberRule, - MethodRule, PropertyRule, -} from './api'; - -export class MethodStartsWithZ extends MethodRule { - - report(method: Method): Diagnostic[] { - const diagnostics: Diagnostic[] = []; - - startsWithZ(method, diagnostics, this.ruleName); - - return diagnostics; - } -} -export class PropertyStartsWithZ extends PropertyRule { - - report(property: Property): Diagnostic[] { - const diagnostics: Diagnostic[] = []; - - startsWithZ(property, diagnostics, this.ruleName); - - return diagnostics; - } -} - -export class PropertyIsDummy extends PropertyRule { - - report(property: Property): Diagnostic[] { - const diagnostics: Diagnostic[] = []; - if (!this.parsedDocument.extending) { - this.isCalledDummy(property, diagnostics); - } - return diagnostics; - } - - isCalledDummy(member: Member, diagnostics: Diagnostic[]): void { - if (member.id.value.toLowerCase() === 'dummy') { - diagnostics.push( - createDiagnostic(member, 'Usage of "dummy" property is discouraged', DiagnosticSeverity.Information, this.ruleName), - ); - } - } -} - -export class PropertyIsDuplicate extends PropertyRule { - - report(property: Property): Diagnostic[] { - const diagnostics: Diagnostic[] = []; - this.isDuplicateProperty(property, diagnostics); - return diagnostics; - } - - isDuplicateProperty(property: Property, diagnostics: Diagnostic[]): void { - - const slicedProperty = this.parsedDocument.properties.slice(0, - this.parsedDocument.properties.findIndex(x => x.id.position.line === property.id.position.line)); - - for (const checkProperty of slicedProperty) { - - if (checkProperty.id.value === property.id.value) { - const diagnostic = new Diagnostic( - property.id.getRange(), - `Property "${property.id.value}" is already declared.`, - this.ruleName, - DiagnosticSeverity.Warning, - ); - const aboveDuplicateProperty = new DiagnosticRelatedInformation( - checkProperty.id.getRange(), - `Reference to property "${checkProperty.id.value}".`, - ); - diagnostic.relatedInformation = [ - aboveDuplicateProperty, - ]; - diagnostic.source = 'lint'; - diagnostics.push(diagnostic); - break; - } - - if (checkProperty.id.value.toLowerCase() === property.id.value.toLowerCase()) { - const diagnostic = new Diagnostic( - property.id.getRange(), - `Property "${property.id.value}" is already declared with different case.`, - this.ruleName, - DiagnosticSeverity.Warning, - ); - const aboveDuplicateProperty = new DiagnosticRelatedInformation( - checkProperty.id.getRange(), - `Reference to property "${checkProperty.id.value}".`, - ); - diagnostic.relatedInformation = [ - aboveDuplicateProperty, - ]; - diagnostic.source = 'lint'; - diagnostics.push(diagnostic); - break; - } - } - } -} - -export class MemberLiteralCase extends MemberRule { - - report(member: Member): Diagnostic[] { - const diagnostics: Diagnostic[] = []; - this.checkUpperCase(member, diagnostics); - return diagnostics; - } - checkUpperCase(member: Property, diagnostics: Diagnostic[]): void { - if ((member.modifiers.findIndex(x => x.value === 'literal') > -1)) { - if (member.id.value !== member.id.value.toUpperCase()) { - diagnostics.push( - createDiagnostic(member, 'is literal but not upper case.', DiagnosticSeverity.Warning, this.ruleName), - ); - } - } - } -} - -export class MemberCamelCase extends MemberRule { - - report(member: Member): Diagnostic[] { - const diagnostics: Diagnostic[] = []; - - this.memberCase(member, diagnostics); - - return diagnostics; - } - - memberCase(member: Member, diagnostics: Diagnostic[]): void { - const isLiteral = (member.modifiers.findIndex(x => x.value === 'literal') > -1); - let isStaticDeclaration = false; - - member.types.forEach(type => { - if (type.value === member.id.value) { - isStaticDeclaration = true; - } - }); - - // exception for variables starting with percentage - if (member.id.value.charAt(0) === '%') return; - // exception for literal properties - if (isLiteral || isStaticDeclaration) return; - - if (member.memberClass === MemberClass.method) { - const method = member as Method; - if (method.batch) return; - } - - if (member.id.value.charAt(0) > 'z' || member.id.value.charAt(0) < 'a') { - if (isPublicDeclaration(member)) { - const diagnostic = new Diagnostic( - member.id.getRange(), - `Declaration "${member.id.value}" is public and does not start with lower case.`, - this.ruleName, - DiagnosticSeverity.Information, - ); - diagnostic.source = 'lint'; - diagnostic.member = member; - diagnostics.push(diagnostic); - } - else { - diagnostics.push(createDiagnostic( - member, - 'does not start with lowercase.', - DiagnosticSeverity.Warning, - this.ruleName, - )); - } - } - } -} - -export class MemberLength extends MemberRule { - - report(member: Member): Diagnostic[] { - const diagnostics: Diagnostic[] = []; - - this.checkMemberLength(member, diagnostics); - - return diagnostics; - } - - checkMemberLength(member: Member, diagnostics: Diagnostic[]): void { - if (member.id.value.length > 25) { - diagnostics.push(createDiagnostic( - member, - 'is longer than 25 characters.', - DiagnosticSeverity.Warning, - this.ruleName, - )); - } - } -} -export class MemberStartsWithV extends MemberRule { - - report(member: Member): Diagnostic[] { - const diagnostics: Diagnostic[] = []; - - this.checkStartsWithV(member, diagnostics); - - return diagnostics; - } - - checkStartsWithV(member: Member, diagnostics: Diagnostic[]): void { - if (member.id.value.charAt(0) !== 'v') return; - if (isPublicDeclaration(member)) { - diagnostics.push(createDiagnostic( - member, - `is public and starts with 'v'.`, - DiagnosticSeverity.Information, - this.ruleName, - )); - } - else { - diagnostics.push(createDiagnostic(member, `starts with 'v'.`, DiagnosticSeverity.Warning, this.ruleName)); - } - } -} - -function createDiagnostic( - member: Member, - message: string, - diagnosticSeverity: DiagnosticSeverity, - ruleName: string, -): Diagnostic { - const diagnostic = new Diagnostic( - member.id.getRange(), - `${printEnum(member.memberClass)} "${member.id.value}" ${message}`, - ruleName, - diagnosticSeverity, - ); - diagnostic.source = 'lint'; - diagnostic.member = member; - return diagnostic; -} - -function startsWithZ(member: Member, diagnostics: Diagnostic[], ruleName: string) { - const firstChar = member.id.value.charAt(0); - if (firstChar === 'z' || firstChar === 'Z') { - diagnostics.push(createDiagnostic( - member, - `starts with '${firstChar}'.`, - DiagnosticSeverity.Information, - ruleName, - )); - } -} -function printEnum(memberClass: MemberClass): string { - const enumName = MemberClass[memberClass]; - const capitalizedEnumName = enumName.charAt(0).toUpperCase() + enumName.slice(1); - return enumName === 'method' ? 'Label' : capitalizedEnumName; -} - -function isPublicDeclaration(member: Member) { - const isPublic = member.modifiers.findIndex(x => x.value === 'public') > -1; - return member.memberClass === MemberClass.declaration && isPublic; -} diff --git a/src/pslLint/methodDoc.ts b/src/pslLint/methodDoc.ts deleted file mode 100644 index c48e851..0000000 --- a/src/pslLint/methodDoc.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Method, ParsedDocument } from '../parser/parser'; -import { Token } from '../parser/tokenizer'; -import { getCommentsOnLine, getLineAfter} from '../parser/utilities'; -import { Diagnostic, DiagnosticSeverity, MethodRule } from './api'; - -export enum Code { - ONE_EMPTY_LINE = 1, - TWO_EMPTY_LINES = 2, -} - -/** - * Checks if method has a documentation block below it. - */ -export class MethodDocumentation extends MethodRule { - - report(method: Method): Diagnostic[] { - - if (method.batch) return []; - - const diagnostics: Diagnostic[] = []; - - if (!hasBlockComment(method, this.parsedDocument)) { - const idToken = method.id; - const message = `Documentation missing for label "${idToken.value}".`; - diagnostics.push(addDiagnostic(idToken, method, message, this.ruleName)); - } - - return diagnostics; - } -} -export class MethodSeparator extends MethodRule { - - report(method: Method): Diagnostic[] { - - if (method.batch) return []; - - const diagnostics: Diagnostic[] = []; - - if (!hasSeparator(method, this.parsedDocument)) { - const idToken = method.id; - const message = `Separator missing for label "${idToken.value}".`; - diagnostics.push(addDiagnostic(idToken, method, message, this.ruleName)); - } - - return diagnostics; - } -} - -export class TwoEmptyLines extends MethodRule { - - report(method: Method): Diagnostic[] { - - if (method.batch) return []; - - const diagnostics: Diagnostic[] = []; - const idToken = method.id; - - const lineAbove = hasSeparator(method, this.parsedDocument) ? - method.id.position.line - 2 : method.id.position.line - 1; - - if (lineAbove < 2) { - const message = `There should be two empty lines above label "${idToken.value}".`; - return [addDiagnostic(idToken, method, message, this.ruleName, Code.TWO_EMPTY_LINES)]; - } - - const hasOneSpaceAbove: boolean = this.profileComponent.getTextAtLine(lineAbove).trim() === ''; - const hasTwoSpacesAbove: boolean = this.profileComponent.getTextAtLine(lineAbove - 1).trim() === ''; - const hasThreeSpacesAbove: boolean = this.profileComponent.getTextAtLine(lineAbove - 2).trim() === ''; - - let code: Code | undefined; - if (!hasTwoSpacesAbove) code = Code.ONE_EMPTY_LINE; - if (!hasOneSpaceAbove) code = Code.TWO_EMPTY_LINES; - - // Checks two empty lines above a method - if (!hasOneSpaceAbove || !hasTwoSpacesAbove || lineAbove <= 0) { - const message = `There should be two empty lines above label "${idToken.value}".`; - diagnostics.push(addDiagnostic(idToken, method, message, this.ruleName, code)); - } - - // Check more than 2 empty lines above a method - if (hasOneSpaceAbove && hasTwoSpacesAbove && hasThreeSpacesAbove) { - const message = `There are more than two empty lines above label "${idToken.value}".`; - diagnostics.push(addDiagnostic(idToken, method, message, this.ruleName, code)); - } - - return diagnostics; - } -} - -function addDiagnostic(idToken: Token, method: Method, message: string, ruleName: string, code?: Code): Diagnostic { - const range = idToken.getRange(); - const diagnostic = new Diagnostic(range, message, ruleName, DiagnosticSeverity.Information); - diagnostic.source = 'lint'; - diagnostic.member = method; - if (code) diagnostic.code = code; - return diagnostic; -} - -function hasSeparator(method: Method, parsedDocument: ParsedDocument): boolean { - const nextLineCommentTokens: Token[] = getCommentsOnLine(parsedDocument, method.id.position.line - 1); - return nextLineCommentTokens[0] && nextLineCommentTokens[0].isLineComment(); -} - -function hasBlockComment(method: Method, parsedDocument: ParsedDocument): boolean { - const nextLineCommentTokens: Token[] = getCommentsOnLine(parsedDocument, getLineAfter(method)); - return nextLineCommentTokens[0] && nextLineCommentTokens[0].isBlockComment(); -} diff --git a/src/pslLint/multiLineDeclare.ts b/src/pslLint/multiLineDeclare.ts deleted file mode 100644 index d0c3fc6..0000000 --- a/src/pslLint/multiLineDeclare.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Declaration, Method, NON_TYPE_MODIFIERS } from '../parser/parser'; -import { getTokens } from '../parser/tokenizer'; -import { Diagnostic, DiagnosticSeverity, MethodRule } from './api'; - -export class MultiLineDeclare extends MethodRule { - - report(method: Method): Diagnostic[] { - - const diagnostics: Diagnostic[] = []; - let reportVariable: boolean = false; - - const multiLineDeclarations = this.getMultiLineDeclarations(method.declarations); - - multiLineDeclarations.forEach((declarationsOnLine, lineNumber) => { - const fullLine = this.profileComponent.getTextAtLine(lineNumber); - if (!(fullLine.includes('=') && fullLine.includes(','))) return; - for (const declaration of declarationsOnLine) { - reportVariable = false; - let conditionOpen: boolean = false; - let commaFound: boolean = false; - let conditionClose: boolean = false; - let typePresent: boolean = false; - for (const token of getTokens(fullLine)) { - if (token.isWhiteSpace()) continue; - if (token.isDoubleQuotes()) continue; - if (token.isBlockCommentInit()) continue; - if ((token.value) === 'type') { - typePresent = true; - continue; - } - if (NON_TYPE_MODIFIERS.indexOf(token.value) > -1) { - continue; - } - if (declaration.types.map(t => t.value).indexOf(token.value) > -1) { - continue; - } - if (token.isOpenParen()) { - conditionOpen = true; - conditionClose = false; - continue; - } - if (conditionOpen && token.isCloseParen()) { - conditionClose = true; - continue; - } - if (token.isComma()) { - commaFound = true; - continue; - } - if (commaFound && token.isEqualSign() && typePresent && conditionOpen === conditionClose) { - conditionOpen = false; - conditionClose = false; - commaFound = false; - reportVariable = true; - } - } - if (reportVariable) { - const diagnostic = new Diagnostic( - declaration.id.getRange(), - `Declaration ${declaration.id.value} should be initialized on a new line.`, - this.ruleName, - DiagnosticSeverity.Warning, - ); - diagnostic.source = 'lint'; - diagnostics.push(diagnostic); - } - } - }); - return diagnostics; - } - getMultiLineDeclarations(declarations: Declaration[]): Map { - const data = new Map(); - declarations.forEach(declaration => { - const lineNumber = declaration.id.position.line; - const declarationsOnLine = data.get(lineNumber); - if (declarationsOnLine) declarationsOnLine.push(declaration); - else data.set(lineNumber, [declaration]); - }); - data.forEach((declarationArray, lineNumber) => { - if (declarationArray.length <= 1) { - data.delete(lineNumber); - } - }); - return data; - } -} diff --git a/src/pslLint/parameters.ts b/src/pslLint/parameters.ts deleted file mode 100644 index 318d95a..0000000 --- a/src/pslLint/parameters.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Method, Parameter } from '../parser/parser'; -import { Diagnostic, DiagnosticSeverity, MethodRule } from './api'; - -/** - * Checks if multiple parameters are written on the same line as the method declaration. - */ -export class MethodParametersOnNewLine extends MethodRule { - - report(method: Method): Diagnostic[] { - - if (method.batch) return []; - - const diagnostics: Diagnostic[] = []; - const methodLine = method.id.position.line; - - let previousParam: Parameter | undefined; - for (const param of method.parameters) { - const paramPosition = param.id.position; - if (previousParam && paramPosition.line === previousParam.id.position.line) { - const message = `Parameter "${param.id.value}" on same line as parameter "${previousParam.id.value}".`; - const diagnostic = new Diagnostic(param.id.getRange(), message, this.ruleName, DiagnosticSeverity.Warning); - diagnostic.source = 'lint'; - diagnostics.push(diagnostic); - } - else if (method.parameters.length > 1 && paramPosition.line === methodLine) { - const message = `Parameter "${param.id.value}" on same line as label "${method.id.value}".`; - const diagnostic = new Diagnostic(param.id.getRange(), message, this.ruleName, DiagnosticSeverity.Warning); - diagnostic.source = 'lint'; - diagnostics.push(diagnostic); - } - previousParam = param; - } - - return diagnostics; - } -} diff --git a/src/pslLint/runtime.ts b/src/pslLint/runtime.ts deleted file mode 100644 index 5305a20..0000000 --- a/src/pslLint/runtime.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { Member, MemberClass, Method } from '../parser/parser'; -import { - BinaryOperator, Identifier, - StringLiteral, SyntaxKind, Value, -} from '../parser/statementParser'; -import { Range, Token } from '../parser/tokenizer'; -import { getCommentsOnLine } from '../parser/utilities'; -import { Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, MethodRule } from './api'; - -export class RuntimeStart extends MethodRule { - - report(method: Method): Diagnostic[] { - - const runtimeCalls: BinaryOperator[] = []; - - method.statements.filter(statement => { - return statement.action.value === 'do'; - }).forEach(statement => { - statement.expressions.forEach(expression => { - const dotOperator = expression as BinaryOperator; - const classIdentifier = this.getClass(dotOperator); - if (!classIdentifier) return; - if (classIdentifier.id.value === 'Runtime') runtimeCalls.push(dotOperator); - }); - }); - - if (!runtimeCalls.length) return []; - - const diagnostics: Diagnostic[] = []; - this.tpFence(diagnostics, runtimeCalls, method); - return diagnostics; - } - - getClass(dotOperator: BinaryOperator): Identifier | undefined { - if (dotOperator.kind !== SyntaxKind.BINARY_OPERATOR) return; - if (Array.isArray(dotOperator.left)) return; - if (!dotOperator.left || dotOperator.left.kind === SyntaxKind.BINARY_OPERATOR) return; - return dotOperator.left as Identifier; - } - - getMethod(dotOperator: BinaryOperator): Identifier | undefined { - if (dotOperator.kind !== SyntaxKind.BINARY_OPERATOR) return; - return dotOperator.right as Identifier; - } - - tpFence( - diagnostics: Diagnostic[], - runtimeCalls: BinaryOperator[], - method: Method, - ): void { - let lastStart: Value; - let variables: Map; - let acceptVariables: string[] = []; - for (const runtimeCall of runtimeCalls) { - const runtimeMethod = this.getMethod(runtimeCall); - if (runtimeMethod.id.value === 'start') { - if (lastStart) { - variables.forEach((identifiers, variable) => { - this.createDiagnostic(lastStart, variable, identifiers, diagnostics); - }); - } - lastStart = runtimeMethod; - variables = new Map(); - acceptVariables = this.addToWhitelist(runtimeMethod); - } - else if (runtimeMethod.id.value === 'commit') { - if (!lastStart) continue; - else { - const startLine = lastStart.id.position.line; - const commitLine = runtimeMethod.id.position.line; - const identifierTokens: Token[] = this.getAllIdentifersInRange( - this.parsedDocument.tokens, - startLine, - commitLine, - ); - const variablesOutsideStart: Member[] = method.declarations.concat(method.parameters) - .filter(variable => { - return variable.id.position.line <= startLine && acceptVariables.indexOf(variable.id.value) === -1; - }); - for (const token of identifierTokens) { - this.addVariable(variablesOutsideStart, token, lastStart, variables); - } - - } - } - } - if (variables) { - variables.forEach((identifiers, variable) => { - this.createDiagnostic(lastStart, variable, identifiers, diagnostics); - }); - } - - } - private getAllIdentifersInRange(tokens: Token[], startLine: number, commitLine: number): Token[] { - return tokens.filter(token => { - return token.position.line > startLine && token.position.line < commitLine; - }); - } - - private createDiagnostic(lastStart: Value, variable: Member, identifiers: Token[], diagnostics: Diagnostic[]) { - const range = this.getDiagnosticRange(lastStart); - const word = variable.memberClass === MemberClass.parameter ? 'Parameter' : 'Declaration'; - const diag = new Diagnostic( - range, - `${word} "${variable.id.value}" referenced inside Runtime.start but not in variable list.`, - this.ruleName, - DiagnosticSeverity.Warning, - variable, - ); - const relatedSource = new DiagnosticRelatedInformation( - variable.id.getRange(), - `Source of "${variable.id.value}"`, - ); - const relatedReferences = identifiers.map(i => { - return new DiagnosticRelatedInformation(i.getRange(), `Reference to "${i.value}"`); - }); - diag.relatedInformation = [ - relatedSource, - ...relatedReferences, - ]; - diag.source = 'tpfence'; - diagnostics.push(diag); - } - - private addVariable( - localVariablesOutsideStart: Member[], - identifierToken: Token, - start: Identifier, - variables: Map, - ) { - const variable = localVariablesOutsideStart.find(v => v.id.value === identifierToken.value); - if ( - variable - && variable.id !== variable.types[0] - && variable.modifiers.map(m => m.value).indexOf('literal') === -1 - ) { // no static and literal - const varList = start.args[1] as StringLiteral; - if (!varList || varList.id.value.split(',').indexOf(variable.id.value) === -1) { - const tokens = variables.get(variable); - if (!tokens) { - variables.set(variable, [identifierToken]); - } - else if (tokens.indexOf(identifierToken) === -1) { - variables.set(variable, tokens.concat([identifierToken])); - } - } - } - } - - private getDiagnosticRange(start: Identifier): Range { - const startPos = start.id.position.character - 'do Runtime.'.length; - const endPos = start.closeParen.position.character + 1; - return new Range(start.id.position.line, startPos, start.id.position.line, endPos); - } - - private addToWhitelist(runtimeMethod: Identifier) { - let acceptVariables: string[] = []; - const commentsAbove: Token[] = getCommentsOnLine(this.parsedDocument, runtimeMethod.id.position.line - 1); - const whiteListComment = commentsAbove[0]; - if (!whiteListComment || !whiteListComment.isLineComment()) return []; - - const comment = whiteListComment.value.trim(); - if (!comment.startsWith('@psl-lint.RuntimeStart')) return []; - - const args = comment.replace(/^@psl-lint\.RuntimeStart\s+/, '').split('='); - for (let i = 0; i < args.length; i += 2) { - const arg = args[i]; - const value = args[i + 1]; - if (arg === 'accept' && value) { - const strippedValue = value.replace(/"/g, ''); - acceptVariables = strippedValue.split(','); - } - } - - return acceptVariables; - } -} diff --git a/src/pslLint/tblcolDoc.ts b/src/pslLint/tblcolDoc.ts deleted file mode 100644 index 1812345..0000000 --- a/src/pslLint/tblcolDoc.ts +++ /dev/null @@ -1,43 +0,0 @@ -import * as path from 'path'; -import { Range } from '../parser/tokenizer'; -import { Diagnostic, DiagnosticSeverity, FileDefinitionRule } from './api'; - -/** - * Checks whether table and columns are created with documentation. - */ -export class TblColDocumentation extends FileDefinitionRule { - - report(): Diagnostic[] { - const baseName = path.basename(this.profileComponent.fsPath); - - const diagnostics: Diagnostic[] = []; - const bracketMatch = this.profileComponent.textDocument.match(/^}/m); - // Exit if no match found - if (!bracketMatch) return []; - - const charcterOffset = bracketMatch.index; - const endPos = this.profileComponent.textDocument.length; - const tblColDoc = this.profileComponent.textDocument.substring(charcterOffset + 1, endPos).trim(); - - if (!tblColDoc) { - let message; - - if (baseName.endsWith('TBL')) { - message = `Documentation missing for table definition "${baseName}".`; - } - else message = `Documentation missing for data item "${baseName}".`; - const position = this.profileComponent.positionAt(charcterOffset); - const range = new Range(position, position); - diagnostics.push(addDiagnostic(range, message, this.ruleName)); - } - - return diagnostics; - } - -} - -function addDiagnostic(range: Range, message: string, ruleName: string): Diagnostic { - const diagnostic = new Diagnostic(range, message, ruleName, DiagnosticSeverity.Information); - diagnostic.source = 'lint'; - return diagnostic; -} diff --git a/src/pslLint/todos.ts b/src/pslLint/todos.ts deleted file mode 100644 index 2bb7466..0000000 --- a/src/pslLint/todos.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { getTokens, Position, Range } from '../parser/tokenizer'; -import { Diagnostic, DiagnosticSeverity, PslRule } from './api'; - -export class TodoInfo extends PslRule { - - report(): Diagnostic[] { - let todos: Todo[] = []; - for (const token of this.parsedDocument.comments) { - if (token.value.includes('TODO')) { - const startLine = token.position.line; - const startChar = token.position.character; - todos = todos.concat(getTodosFromComment(token.value, startLine, startChar)); - } - } - return todos.map(todo => { - const diagnostic = new Diagnostic(todo.range, todo.message, this.ruleName, DiagnosticSeverity.Information); - diagnostic.source = 'TODO'; - return diagnostic; - }); - } -} - -interface Todo { - range: Range; - message: string; -} - -function getTodosFromComment(commentText: string, startLine: number, startChar: number): Todo[] { - let todos: Todo[] = []; - let todo: Todo | undefined; - let currentLine: number; - let currentChar: number; - - const finalize = () => { - if (!todo) return; - const start = todo.range.start; - const end = new Position(currentLine, todo.range.end.character + todo.message.trimRight().length); - todo.range = new Range(start, end); - todo.message = todo.message.trim().replace(/^:/gm, '').trim(); - if (!todo.message) todo.message = `TODO on line ${todo.range.start.line + 1}.`; - todos.push(todo); - todo = undefined; - }; - - const tokens = getTokens(commentText); - for (const token of tokens) { - currentLine = startLine + token.position.line; - currentChar = startLine === currentLine ? token.position.character + startChar : token.position.character; - if (token.isBlockCommentInit() || token.isLineCommentInit()) continue; - else if (token.isBlockComment() || token.isLineComment()) { - todos = todos.concat(getTodosFromComment(token.value, currentLine, currentChar)); - } - else if (token.value === 'TODO' && !todo) { - const range = new Range(currentLine, currentChar, currentLine, currentChar + 4); - const message = ''; - todo = { range, message }; - } - else if (todo) { - if (token.isNewLine()) finalize(); - else todo.message += token.value; - } - } - if (todo) finalize(); - return todos; -} diff --git a/syntaxes/JSON.tmLanguage b/syntaxes/JSON.tmLanguage deleted file mode 100644 index 61d005e..0000000 --- a/syntaxes/JSON.tmLanguage +++ /dev/null @@ -1,386 +0,0 @@ - - - - - fileTypes - - json - sublime-settings - sublime-menu - sublime-keymap - sublime-mousemap - sublime-theme - sublime-build - sublime-project - sublime-completions - - foldingStartMarker - (?x) # turn on extended mode - ^ # a line beginning with - \s* # some optional space - [{\[] # the start of an object or array - (?! # but not followed by - .* # whatever - [}\]] # and the close of an object or array - ,? # an optional comma - \s* # some optional space - $ # at the end of the line - ) - | # ...or... - [{\[] # the start of an object or array - \s* # some optional space - $ # at the end of the line - foldingStopMarker - (?x) # turn on extended mode - ^ # a line beginning with - \s* # some optional space - [}\]] # and the close of an object or array - keyEquivalent - ^~J - name - JSON (Javascript Next) - patterns - - - include - #value - - - repository - - array - - begin - \[ - beginCaptures - - 0 - - name - punctuation.definition.array.begin.json - - - end - \] - endCaptures - - 0 - - name - punctuation.definition.array.end.json - - - name - meta.structure.array.json - patterns - - - include - #value - - - match - , - name - punctuation.separator.array.json - - - match - [^\s\]] - name - invalid.illegal.expected-array-separator.json - - - - comments - - patterns - - - begin - /\*\* - captures - - 0 - - name - punctuation.definition.comment.json - - - end - \*/ - name - comment.block.documentation.json - - - begin - /\* - captures - - 0 - - name - punctuation.definition.comment.json - - - end - \*/ - name - comment.block.json - - - captures - - 1 - - name - punctuation.definition.comment.json - - - match - (//).*$\n? - name - comment.line.double-slash.js - - - - constant - - match - \b(?:true|false|null)\b - name - constant.language.json - - number - - match - (?x) # turn on extended mode - -? # an optional minus - (?: - 0 # a zero - | # ...or... - [1-9] # a 1-9 character - \d* # followed by zero or more digits - ) - (?: - (?: - \. # a period - \d+ # followed by one or more digits - )? - (?: - [eE] # an e character - [+-]? # followed by an option +/- - \d+ # followed by one or more digits - )? # make exponent optional - )? # make decimal portion optional - name - constant.numeric.json - - object - - begin - \{ - beginCaptures - - 0 - - name - punctuation.definition.dictionary.begin.json - - - end - \} - endCaptures - - 0 - - name - punctuation.definition.dictionary.end.json - - - name - meta.structure.dictionary.json - patterns - - - comment - the JSON object key - include - #objectkey - - - include - #comments - - - begin - : - beginCaptures - - 0 - - name - punctuation.separator.dictionary.key-value.json - - - end - (,)|(?=\}) - endCaptures - - 1 - - name - punctuation.separator.dictionary.pair.json - - - name - meta.structure.dictionary.value.json - patterns - - - comment - the JSON object value - include - #value - - - match - [^\s,] - name - invalid.illegal.expected-dictionary-separator.json - - - - - match - [^\s\}] - name - invalid.illegal.expected-dictionary-separator.json - - - - string - - begin - " - beginCaptures - - 0 - - name - punctuation.definition.string.begin.json - - - end - " - endCaptures - - 0 - - name - punctuation.definition.string.end.json - - - name - string.quoted.double.json - patterns - - - include - #stringcontent - - - - objectkey - - begin - " - beginCaptures - - 0 - - name - punctuation.support.type.property-name.begin.json - - - end - " - endCaptures - - 0 - - name - punctuation.support.type.property-name.end.json - - - name - support.type.property-name.json - patterns - - - include - #stringcontent - - - - stringcontent - - patterns - - - match - (?x) # turn on extended mode - \\ # a literal backslash - (?: # ...followed by... - ["\\/bfnrt] # one of these characters - | # ...or... - u # a u - [0-9a-fA-F]{4}) # and four hex digits - name - constant.character.escape.json - - - match - \\. - name - invalid.illegal.unrecognized-string-escape.json - - - - value - - patterns - - - include - #constant - - - include - #number - - - include - #string - - - include - #array - - - include - #object - - - include - #comments - - - - - scopeName - source.json - uuid - 8f97457b-516e-48ce-83c7-08ae12fb327a - - \ No newline at end of file diff --git a/syntaxes/psl.tmLanguage.json b/syntaxes/psl.tmLanguage.json deleted file mode 100644 index 031f320..0000000 --- a/syntaxes/psl.tmLanguage.json +++ /dev/null @@ -1,530 +0,0 @@ -{ - "comment": "Syntax highlighting for the Profile Scripting Langauge (PSL) and M", - "comment": " ", - "comment": "The order of the includes and mataches in the patterns is significant", - "comment": "The order of the repository entries is not and occur in alpabetic order.", - "comment": " ", - "comment": "Known issues:", - "comment": " * A statement on a line with a non-numeric label (i.e., no formal-list) is classified as entity.name.function.psl", - "comment": " * A local method occurrence in a do statement is classified as entity.name.unknown.psl", - - "name": "Profile Scripting Language", - "scopeName": "source.psl", - "patterns": [ - { "include": "#comments", "comment": "PSL comment-block, PSL comment-to-end-of-line, and M comment-to-end-of-line"}, - { "include": "#accept-directive", "comment": "#ACCEPT directive with all text following the directive considered comment"}, - { "include": "#classdef-directive", "comment": "#CLASSDEF directive with qualifiers"}, - { "include": "#if-directive", "comment": "#IF and #ELSEIF directives (followed by PSL code)"}, - { "include": "#optimize-directive", "comment": "#OPTIMIZE directive"}, - { "include": "#option-directive", "comment": "#OPTION directive"}, - { "include": "#package-directive", "comment": "#PACKAGE directive with root-package and optional sub-packages"}, - { "include": "#propertydef-directive", "comment": "#PROPERTYDEF directive with qualifiers"}, - { "include": "#warn-directive", "comment": "#INFO and #WARN directives"}, - { "include": "#other-directive", "comment": "#BYPASS, #ELSE, #END, #ENDBYPASS, and #ENDIF directives"}, - { "include": "#method-declaration", "comment": "method declaration"}, - { "include": "#label-declaration", "comment": "label declaration (method declaration without formal-list"}, - { "include": "#statements", "comment": "PSL statements"}, - { "include": "#literals", "comment": "Numeric literals and string literals"}, - { "include": "#special-constructs", "comment": "true/false, this/super, system keywords"}, - { "include": "#modifiers", "comment": "private, protected, literal, readonly, etc."}, - { "include": "#name-in-context", "comment": "class name, method name, proprty name, and variable name"} - ], - "repository": { - "accept-directive": { - "comment": "#ACCEPT PSL code generator directive. All text following the directive is rendered as comment.", - "match": "^\\s+(#ACCEPT)(.*)", - "captures": { - "1": { "name": "constant.language.codegeneratorDirective.accept.psl"}, - "2": { "name": "comment.inline.psl"} - } - }, - "class-names": { - "patterns": [ - { "include": "#psl-language-class" - }, - { "comment": "All other names that occur when a class name is expected.", - "name": "entity.name.class.psl", - "match": "[%A-Za-z][A-Za-z0-9]*" - } - ] - }, - "classdef-directive": { - "match": "^\\s+(#CLASSDEF)(\\s+)(.*)", - "captures": { - "1": { "name": "constant.language.classdef.psl"}, - "3": { - "patterns": [ - { "name": "keyword.other.classdef.psl", "match": "(extends|delimiter)"}, - { "name": "storage.modifier.visibility.psl", "match": "\\b(public)\\b"}, - { "include": "#class-names"} - ] - } - } - }, - "comments": { - "patterns": [ - { "include": "#comments-inline-m"}, - { "include": "#comments-inline-psl"}, - { "include": "#comments-psldoc", "comment": "This rule must occur *before* the rule for a (standard) comment block."}, - { "include": "#comments-block"} - ] - }, - "comments-block": { - "begin": "/\\*", - "end": "\\*/", - "name": "comment.block.psl", - "captures": { - "0": { "name": "punctuation.definition.comment.psl"} - }, - "patterns": [ - { "include": "#comments-inline-m"}, - { "include": "#comments-inline-psl"}, - { "include": "#doc-params"}, - { "include": "#todo"} - ] - }, - "comments-inline-m": { - "begin": ";", - "beginCaptures": { - "0": { "name": "punctuation.definition.comment.psl"} - }, - "end": "\\n", - "name": "comment.line.semicolon.psl", - "patterns": [ - { "include": "#doc-params"}, - { "include": "#todo"} - ] - }, - "comments-inline-psl": { - "begin": "//", - "beginCaptures": { - "0": { "name": "punctuation.definition.comment.psl"} - }, - "end": "\\n", - "name": "comment.line.double-slash.psl", - "patterns": [ - { "include": "#doc-params"}, - { "include": "#todo"} - ] - }, - "comments-psldoc": { - "begin": "/\\* *DOC *", - "end": "(\\*\\* *ENDDOC *\\*/|\\*/)", - "name": "comment.block.documentation.psl", - "captures": { - "0": { "name": "punctuation.definition.comment.psl"} - }, - "patterns": [ - { "include": "#comments-inline-m"}, - { "include": "#comments-inline-psl"}, - { "include": "#doc-params"}, - { "include": "#todo"} - ] - }, - "doc-params": { - "patterns": [ - { "comment": "PSL DOC subsections with an identifier.", - "match": "(@(args|param|publicnew|public|throws?))(\\s*)([A-Za-z\\-0-9%_\\.]+)", - "captures": { - "1": { "comment": "The PSL DOC subsection keyword.", - "name": "markup.heading.jsdoc" - }, - "4": { "comment": "The variable or error ID.", - "name": "variable.other.jsdoc" - } - } - }, - { "comment": "PSL DOC subsections without an identifier.", - "match": "@created|@return|@when?", - "name": "markup.heading.jsdoc" - } - ] - }, - "formal-parameter": { - "name": "meta.function.formal-parameter.psl", - "patterns": [ - { "match": "(\\s*)(noreq\\s+ret\\s+|noreq\\s+|req\\s+ret\\s+|req\\s+|ret\\s+)?([%A-Za-z][A-Za-z0-9]*\\s+)?([%A-Za-z][A-Za-z0-9]*)(\\((,?\\s*([%A-Za-z][A-Za-z0-9]*)?\\s*)*\\))?", - "captures": { - "2": { "name": "storage.modifier.formal-argument.psl"}, - "3": { "patterns": [ - { "include": "#class-names"} ] - }, - "4": { "name": "variable.parameter.psl"}, - "5": { "patterns": [ - { "include": "#class-names"} ] - }, - "6": { "patterns": [ - { "include": "#class-names"} ] - } - } - } - ] - }, - "if-directive": { - "comment": "PSL code genertor directives that are followed by PSL code", - "match": "^\\s+(#IF|#ELSEIF)\\b(.*)", - "captures": { - "1": { "name": "constant.language.codeGeneratorDirective.psl"}, - "2": { "patterns": [ - { "include": "#statements", "comment": "Try statements prior to class names in case the line constains a label and statements."}, - { "include": "#literals", "comment": "Numeric literals and string literals"}, - { "include": "#special-constructs", "comment": "true/false, this/super, system keywords"}, - { "include": "#name-in-context", "comment": "class name, method name, proprty name, and variable name"}, - { "include": "#comments-inline-m"}, - { "include": "#comments-inline-psl"} - ] } - } - }, - "label-declaration": { - "comment": "A label declaration is a method declaration without a formal parameter list.", - "comment": "Like a method, it starts in the first position of the line, but there are", - "comment": "fewer variations that we need to account for.", - "comment": "In its most extensive form it only has the following components:", - "comment": "", - "comment": "* accessModifier methodName // comment", - "comment": "", - "comment": "However, the following scenario als needs to be recognized:", - "comment": "* methodName statement ...", - "comment": "", - "name": "meta.function.label.psl", - "match": "^((([%A-Za-z][A-Za-z0-9]*)\\s+)?)([0-9]+|[%A-Za-z][A-Za-z0-9]*)(.*)", - "captures": { - "2": { "patterns": [ - { "comment": "access modifier:", "include": "#modifiers"}, - { "comment": "label followed by statement:", "name": "entity.name.function.psl"} - ] }, - "4": { "name": "entity.name.function.psl" }, - "5": { "patterns": [ - { "include": "#statements", "comment": "Try statements prior to class names in case the line constains a label and statements." }, - { "include": "#literals", "comment": "Numeric literals and string literals"}, - { "include": "#special-constructs", "comment": "true/false, this/super, system keywords"}, - { "include": "#name-in-context", "comment": "class name, method name, proprty name, and variable name"}, - { "include": "#comments-inline-m"}, - { "include": "#comments-inline-psl"} - ]} - } - }, - "literals": { - "patterns": [ - { "comment": "Non-integer values", - "name": "constant.numeric.decimal.psl", - "match": "(?:\\b|(?<=_))[0-9]*\\.[0-9]+(?=\\b|_)" - }, - { "comment": "Integer values", - "name": "constant.numeric.integer.psl", - "match": "(?:\\b|(?<=_))[0-9]+(?=\\b|_)" - }, - { "include": "#strings", "comment": "PSL String (double quoted"} - ] - }, - "method-declaration": { - "comment": "A method declaration starts in the first position of the line.", - "comment": "There are many variations that we need to account for.", - "comment": "In its most extensive form it has the following components:", - "comment": "", - "comment": "* accessModifier storageModifier resultClass methodName ( formal-list ) // comment", - "comment": "", - "comment": "From a syntax highlighting perspective, only the methodName is required", - "comment": "and in an M routine the '// comment' can also be arbitrary M code.", - "comment": "", - "name": "meta.function.method.psl", - "begin": "^(((([%A-Za-z][A-Za-z0-9]*)\\s+)*)([%A-Za-z][A-Za-z0-9]*)\\s+)*([%A-Za-z][A-Za-z0-9]*)\\(", - "beginCaptures": { - "2": { "patterns": [ - { "comment": "access modifier:", "include": "#modifiers"} - ] }, - "5": { "patterns": [ - { "include": "#modifiers"}, - { "include": "#class-names"} - ] }, - "6": { "name": "entity.name.function.psl" - } - }, - "end": "\\)", - "patterns": [ - { "include": "#formal-parameter"}, - { "include": "#comments-inline-psl"} - ] - }, - "modifiers": { - "patterns": [ - { "comment": "storage modifiers", - "name": "storage.modifier.psl", - "match": "\\b(final|literal|readonly|static)\\b" - }, - { "comment": "visibility modifiers", - "name": "storage.modifier.visibility.psl", - "match": "\\b(public|protected|private)\\b" - } - ] - }, - "name-in-context": { "comment": "try to guess the kind of name based on the surrounding characters", - "patterns": [ - { "comment": "$$name ==> method name", - "name": "entity.name.function.psl", - "match": "\\$\\$([%A-Za-z][A-Za-z0-9]*)" - }, - { "comment": "$select() PSL language function", - "name": "support.function.psl", - "match": "(\\$select)(?=\\()" - }, - { "comment": ".name( ==> a method name (or tree property)", - "name": "entity.name.function.psl", - "match": "(\\.[%A-Za-z][A-Za-z0-9]*)(?=\\()" - }, - { "comment": ".name ==> a property name (note that this must follow the check for method)", - "name": "variable.other.propertydef.psl", - "match": "(\\.[%A-Za-z][A-Za-z0-9]*)" - }, - { "comment": "^routine = class name)", - "name": "entity.name.class.psl", - "match": "(\\^[%A-Za-z][A-Za-z0-9]*)" - }, - { "comment": "PSL language classes are usually valid in any context", - "comment": "they take precedence over other static methods or properties.", - "include": "#psl-language-class" - }, - { "comment": "name. ==> instance variable (or class name in case of static method orproperty)", - "name": "variable.other.instanceOrStatic.psl", - "match": "([%A-Za-z][A-Za-z0-9]*)(?=\\.)" - }, - { "comment": "name^ ==> method name", - "name": "entity.name.function.psl", - "match": "([%A-Za-z][A-Za-z0-9]*)(?=\\^)" - }, - { "comment": "Keyword 'ret' in actual parameter list", - "name": "storage.modifier.actual-list.psl", - "match": "\\bret\\s+" - }, - { "comment": "If nothing else matches, try if it is a PSL/M name", - "name": "entity.name.unknown.psl", - "match": "[%A-Z-a-z][A-Z-a-z0-9]*" - } - ] - }, - "optimize-directive": { - "comment": "#OPTIMIZE directive", - "match": "^\\s+(#OPTIMIZE)(\\s+)(.*)", - "captures": { - "1": { "name": "constant.language.codeGeneratorDirective.optimize.psl"}, - "3": { "patterns": [ - {"include": "#optimize-keywords"}, - {"match": "(ON|OFF)", "name": "constant.language.psl"} - ] } - } - }, - "optimize-keywords": { - "comment": "Active and deprecated OPTIMIZE keywords", - "patterns": [ - {"match": "(CUVARLITERAL|OBJECTS)", "name": "keyword.other.optimize.psl"}, - {"match": "(FUNCTIONS)", "name": "invalid.keyword.other.optimize.psl"} - ] - }, - "option-directive": { - "comment": "#OPTION directive", - "match": "^\\s+(#OPTION)(\\s+)(.*)", - "captures": { - "1": { "name": "constant.language.codeGeneratorDirective.option.psl"}, - "3": { "patterns": [ - {"include": "#option-keywords"}, - {"match": "(ON|OFF)", "name": "constant.language.psl"} - ] } - } - }, - "option-keywords": { - "comment": "Active and deprecated #OPTION keywords", - "patterns": [ - {"match": "(IncludePSL|ResultClass)", "name": "keyword.other.option-keyword.psl"}, - {"match": "(\\$GetEFD|AutoPublicERRM|nolink)", "name": "invalid.keyword.other.option-keyword.psl"} - ] - }, - "other-directive": { - "comment": "PSL code genertor directives that stand alone. All text follwoing the directive is ignored (treated as comment).", - "match": "^\\s+(#BYPASS|#ELSE|#END|#ENDBYPASS|#ENDIF)\\b(.*)", - "captures": { - "1": { "name": "constant.language.codeGeneratorDirective.psl"}, - "2": { "name": "comment.inline.psl"} - } - }, - "package-directive": { - "comment": "#PACKAGE directive, followed by root package and optionally subpackages", - "match": "^\\s+(#PACKAGE)(\\s+)([A-Za-z][A-Za-z0-9]*)(\\.[A-Za-z][A-Za-z0-9]*)*", - "captures": { - "1": { "name": "constant.language.codeGeneratorDirective.package.psl"}, - "3": { "name": "entity.name.rootPackage.psl"}, - "4": { "name": "entity.name.subPackage.psl"} - } - }, - "propertydef-directive": { - "match": "^\\s+(#PROPERTYDEF)(\\s+)([%A-Za-z][A-Za-z0-9]*)(.*)", - "captures": { - "1": { "name": "constant.language.propertydef.psl"}, - "3": { "name": "entity.name.other.property.psl"}, - "4": { - "patterns": [ - { "name": "keyword.other.propertydef.psl", "match": "(class|node|position)"}, - { "include": "#modifiers"}, - { "include": "#special-constructs"}, - { "include": "#literals"}, - { "include": "#class-names"} - ] - } - } - }, - "psl-language-class": { - "comment": "Keyword 'void', PSL Language classes, and Record descendants.", - "name": "support.class.language.psl", - "match": "(?:\\b|(?<=_))(void|Boolean|ByteString|Class|Column|Date|Db|DbSet|Error|Host|Integer|IO|List|Number|Object|Primitive|PSL|PslColumnChange|PslJsonObject|Reference|ResultSet|Row|RowSet|Runtime|String|Time|DbsMakerCheckerDlgt|FwkAuthenticate|FwkHostSTF|FwkRestriction|FwkRestrictionOvr|PslDateDlgt|PslMapDlgt|PslMapPathsDlgt|PslNumberDlgt|DBARCHIVE|DbsFunc|DbsFuncUcls|DbsValueDescriptions|FwkErrorLogger|FwkErrorLogReport|FwkEvent|FwkInstCompile|FwkInstTypeInterface|FwkMessage|FwkNotification|FwkStringUtil|PbsPjiCore|PbsPjiProxyVerify|PslMap|PslMapPaths|PslUtAssert|PslUtTestCase|PslUtTestCase4Pbs|PslUtTestSuite|PslUtTestResult|PslUtPbsInterface|Record[A-Za-z0-9]*)(?=\\b|_)" - }, - "special-constructs": { - "patterns": [ - { - "name": "constant.language.psl", - "match": "(?:\\b|(?<=_))(true|false)(?=\\b|_)" - }, - { "comment": "System Keywords that are constant within the PSL process", - "name": "constant.language.systemkeyword.psl", - "match": "(%ModuleName|%ProcessID|%UserDirectory|%UserName)" - }, - { "comment": "System Keywords that are variable within the PSL process but read-only", - "name": "variable.language.systemkeyword.readonly.psl", - "match": "(%CurrentDate|%CurrentTime)" - }, - { "comment": "System Keywords that are variable within the PSL process", - "name": "variable.language.systemkeyword.readwrite.psl", - "match": "(%BatchExit|%BatchRestart|%CompanyName|%EffectiveDate|%Identifier|%ProcessMode|%SessionID|%SystemCurrency|%SystemDate|%UserClass|%UserID|%UserStation)" - }, - { - "match": "(?:\\b|(?<=_))(this|super)(?=\\b|_)", - "name": "variable.language.psl" - } - ] - }, - "statements": { - "patterns": [ - { "comment": "Declaration statement - type static:", - "comment": " * keyword 'type'", - "comment": " * modifier 'static'", - "comment": " * class name", - "match": "\\s+(type\\s+)(static\\s+)([%A-Za-z][A-Za-z0-9]*)", - "captures": { - "1": { "name": "keyword.other.declaration.static.psl"}, - "2": { "name": "storage.modifier.scope.psl"}, - "3": { "patterns": [ - { "include": "#class-names"} - ] } - } - }, - { "comment": "Declaration statement - tree:", - "comment": " 1. keyword 'type'", - "comment": " 2. modifiers 'public new' and 'public'", - "comment": " Note that 'public new' must occur before 'public' !", - "comment": " 3. class name", - "comment": " 4. variable name", - "comment": " 5. ( class name, ... )", - "match": "\\s+(type\\s*)(public\\s+new\\s*|public\\s*)?([%A-Za-z][A-Za-z0-9]*\\s+)([%A-Za-z][A-Za-z0-9]*(\\((,?\\s*([%A-Za-z][A-Za-z0-9]*)\\s*)*\\)))", - "captures": { - "1": { "name": "keyword.other.declaration.tree.psl"}, - "2": { "name": "storage.modifier.scope.psl"}, - "3": { "patterns": [ - { "include": "#class-names"} - ] }, - "4": { "name": "variable.other.psl"}, - "5": { "patterns": [ - { "include": "#class-names"} ] - }, - "6": { "patterns": [ - { "include": "#class-names"} ] - } - } - }, - { "comment": "Declaration statement - deprecated tree:", - "comment": " 1. keyword 'type'", - "comment": " 2. modifiers 'public new', 'public', and 'literal'", - "comment": " Note that 'public new' must occur before 'public' !", - "comment": " 3. class name", - "comment": " 4. variable name", - "comment": " 5. (,...)", - "match": "\\s+(type\\s+)(public\\s+new\\s+|public\\s+|literal\\s+)?([%A-Za-z][A-Za-z0-9]*\\s+)([%A-Za-z][A-Za-z0-9]*)(\\((\\s*,?\\s*)*\\))", - "captures": { - "1": { "name": "keyword.other.declaration.other.psl"}, - "2": { "name": "storage.modifier.scope.psl"}, - "3": { "patterns": [ - { "include": "#class-names"} - ] }, - "4": { "name": "variable.other.psl"}, - "5": { "name": "storage.modifier.deprecated.psl"} - } - }, - { "comment": "Declaration statement - other:", - "comment": " 1. keyword 'type'", - "comment": " 2. modifiers 'public new', 'public', and 'literal'", - "comment": " Note that 'public new' must occur before 'public' !", - "comment": " 3. class name", - "comment": " 4. variable name", - "comment": " 5. , variable name ...", - "match": "\\s+(type\\s+)(public\\s+new\\s+|public\\s+|literal\\s+)?([%A-Za-z][A-Za-z0-9]*\\s+)([%A-Za-z][A-Za-z0-9]*)(((\\s*,)\\s*[%A-Za-z][A-Za-z0-9]*)*)", - "captures": { - "1": { "name": "keyword.other.declaration.other.psl"}, - "2": { "name": "storage.modifier.scope.psl"}, - "3": { "patterns": [ - { "include": "#class-names"} - ] }, - "4": { "name": "variable.other.psl"}, - "5": { "patterns": [ - { "match": "[%A-Za-z][A-Za-z0-9]*", - "name": "variable.other.psl" - } - ] } - } - }, - { "comment": "Control statements", - "match": "\\b(? { } beforeAll(async () => { - filesDir = path.resolve('__tests__', 'files'); + filesDir = path.resolve('test', 'files'); parentFilePath = path.join(filesDir, 'ZParent.PROC'); childFilePath = path.join(filesDir, 'ZChild.PROC'); diff --git a/tsconfig.json b/tsconfig.json index e4b722f..c047352 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,19 +1,20 @@ { "compilerOptions": { - "noUnusedLocals": true, - "noUnusedParameters": true, - "moduleResolution": "node", "module": "commonjs", - "target": "es6", - "outDir": "out", + "target": "es2017", "lib": [ - "es6" + "es2017" ], - "inlineSourceMap": true, - "rootDir": ".", - "skipLibCheck": true + "outDir": "out", + "declaration": true, + "sourceMap": true, + "rootDir": "." + }, + "formatCodeOptions": { + "newLine": "LF" }, "exclude": [ - "node_modules" + "node_modules", + "out" ] }