├── docs
├── .nojekyll
├── assets
│ ├── Extension_01.png
│ ├── Extension_02.png
│ ├── Extension_03.png
│ ├── Migrating_01.png
│ └── Installation_03.png
├── pages
│ ├── general
│ │ └── structure.md
│ ├── cli
│ │ └── installation.md
│ └── extension
│ │ ├── installation.md
│ │ └── index.md
├── _sidebar.md
├── index.html
└── README.md
├── .gitignore
├── cli
├── src
│ ├── extensions.ts
│ ├── targets
│ │ ├── languages
│ │ │ ├── cmd.ts
│ │ │ └── nosrc.ts
│ │ └── languages.ts
│ ├── readFileSystem.ts
│ ├── cli.ts
│ ├── builders
│ │ ├── make
│ │ │ └── folderSettings.ts
│ │ ├── iProject.ts
│ │ └── actions
│ │ │ └── index.ts
│ └── logger.ts
├── test
│ ├── fixtures
│ │ ├── pseudo
│ │ │ ├── qobjs
│ │ │ │ ├── Rules.mk
│ │ │ │ ├── mything.dtaara
│ │ │ │ └── .ibmi.json
│ │ │ └── qrpglesrc
│ │ │ │ ├── .ibmi.json
│ │ │ │ ├── other.pgm.sqlrpgle
│ │ │ │ ├── tester.pgm.rpgle
│ │ │ │ └── Rules.mk
│ │ ├── cldclf
│ │ │ ├── apgm.pgm.clle
│ │ │ └── department.table
│ │ ├── override_objref
│ │ │ ├── .objrefs
│ │ │ ├── PROVIDE1.LF
│ │ │ └── PROVIDER.PF
│ │ ├── dds_deps_with_refs
│ │ │ ├── .objrefs
│ │ │ ├── PROVIDE1.LF
│ │ │ └── PROVIDER.PF
│ │ ├── assume_pgms_copy
│ │ │ ├── qrpgleref
│ │ │ │ └── scooby.rpgle
│ │ │ └── qrpglesrc
│ │ │ │ └── hello.rpgle
│ │ ├── company_system
│ │ │ ├── qsrvsrc
│ │ │ │ ├── banking.bnd
│ │ │ │ └── utils.bnd
│ │ │ ├── qrpgleref
│ │ │ │ ├── utils.rpgleinc
│ │ │ │ └── constants.rpgleinc
│ │ │ ├── qsqlsrc
│ │ │ │ ├── showemps.sql
│ │ │ │ ├── getDouble.sql
│ │ │ │ └── getTotalSalary.sqludf
│ │ │ ├── qrpglesrc
│ │ │ │ ├── banking.sqlrpgle
│ │ │ │ ├── utils.sqlrpgle
│ │ │ │ ├── mypgm.pgm.rpgle
│ │ │ │ └── employees.pgm.sqlrpgle
│ │ │ └── qddssrc
│ │ │ │ ├── department.table
│ │ │ │ ├── employee.table
│ │ │ │ ├── depts.dspf
│ │ │ │ └── emps.dspf
│ │ ├── cs_with_bnddir
│ │ │ ├── qddssrc
│ │ │ │ ├── Rules.mk
│ │ │ │ ├── depts.dspf
│ │ │ │ ├── emps.dspf
│ │ │ │ └── nemp.dspf
│ │ │ ├── qrpglesrc
│ │ │ │ ├── empdet.bnd
│ │ │ │ ├── app.bnddir
│ │ │ │ ├── mypgm.pgm.rpgle
│ │ │ │ └── empdet.sqlrpgle
│ │ │ ├── qtestsrc
│ │ │ │ ├── testing.json
│ │ │ │ └── empdett.test.sqlrpgle
│ │ │ ├── qrpgleref
│ │ │ │ ├── empdet.rpgleinc
│ │ │ │ └── constants.rpgleinc
│ │ │ └── qsqlsrc
│ │ │ │ ├── department.table
│ │ │ │ ├── employee.table
│ │ │ │ └── popdept.sqlprc
│ │ ├── metadata
│ │ │ ├── qobjs
│ │ │ │ ├── mything.dtaara
│ │ │ │ └── .ibmi.json
│ │ │ └── qrpglesrc
│ │ │ │ └── tester.pgm.rpgle
│ │ ├── company_system_no_pgm_ext
│ │ │ ├── qsrvsrc
│ │ │ │ ├── banking.bnd
│ │ │ │ └── utils.bnd
│ │ │ ├── qrpgleref
│ │ │ │ ├── utils.rpgleinc
│ │ │ │ └── constants.rpgleinc
│ │ │ ├── qsqlsrc
│ │ │ │ ├── showemps.sql
│ │ │ │ ├── getDouble.sql
│ │ │ │ └── getTotalSalary.sqludf
│ │ │ ├── qrpglesrc
│ │ │ │ ├── banking.sqlrpgle
│ │ │ │ ├── utils.sqlrpgle
│ │ │ │ ├── mypgm.rpgle
│ │ │ │ └── employees.sqlrpgle
│ │ │ └── qddssrc
│ │ │ │ ├── department.table
│ │ │ │ ├── employee.table
│ │ │ │ ├── depts.dspf
│ │ │ │ └── emps.dspf
│ │ ├── auto_rename1
│ │ │ ├── src
│ │ │ │ └── CBKOPTIMIZ.rpgle
│ │ │ └── LICENSE
│ │ ├── cs_srvpgm
│ │ │ ├── qddssrc
│ │ │ │ ├── actions.json
│ │ │ │ ├── department.table
│ │ │ │ ├── employee.table
│ │ │ │ ├── popdept.sql
│ │ │ │ ├── depts.dspf
│ │ │ │ ├── emps.dspf
│ │ │ │ └── nemp.dspf
│ │ │ ├── qrpglesrc
│ │ │ │ ├── mypgm.pgm.rpgle
│ │ │ │ └── empdet.sqlrpgle
│ │ │ ├── .vscode
│ │ │ │ └── actions.json
│ │ │ ├── qrpgleref
│ │ │ │ ├── empdet.rpgleinc
│ │ │ │ └── constants.rpgleinc
│ │ │ └── qtestsrc
│ │ │ │ └── emptest.test.sqlrpgle
│ │ ├── sql_ref_with
│ │ │ └── sqlwithpgm.pgm.sqlrpgle
│ │ ├── multi_module_two
│ │ │ ├── rpgle
│ │ │ │ ├── runner.pgm.rpgle
│ │ │ │ └── db.sqlrpgle
│ │ │ └── sql
│ │ │ │ └── customer.table
│ │ ├── mixedCaseExport
│ │ │ ├── qsrvsrc
│ │ │ │ └── modexcept.bnd
│ │ │ └── qrpglesrc
│ │ │ │ └── modexcept.sqlrpgle
│ │ ├── from_qsys
│ │ │ ├── qsqlsrc
│ │ │ │ ├── emp.sql
│ │ │ │ ├── dept.sql
│ │ │ │ ├── rsnmst.table
│ │ │ │ ├── prjmst.table
│ │ │ │ └── empmst.sql
│ │ │ └── qprotosrc
│ │ │ │ └── errortable.rpgle
│ │ ├── multi_module
│ │ │ ├── qrpgleref
│ │ │ │ ├── utils.rpgleinc
│ │ │ │ ├── system.rpgleinc
│ │ │ │ └── dataarea.rpgleinc
│ │ │ └── qrpglesrc
│ │ │ │ └── utils.sqlrpgle
│ │ ├── dds_deps
│ │ │ ├── PROVIDE1.LF
│ │ │ └── PROVIDER.PF
│ │ ├── include_fix
│ │ │ └── QRPGLESRC
│ │ │ │ └── ERRORTABLE.rpgleinc
│ │ ├── sql_references
│ │ │ ├── qddssrc
│ │ │ │ └── stock.table
│ │ │ └── qrpglesrc
│ │ │ │ └── sqlrefpgm.pgm.sqlrpgle
│ │ ├── sql_long_names
│ │ │ ├── sql
│ │ │ │ └── trans.table
│ │ │ └── rpgle
│ │ │ │ └── db.sqlrpgle
│ │ ├── dclcase
│ │ │ └── qrpglesrc
│ │ │ │ ├── apival01s.pgm.rpgle
│ │ │ │ └── apival01s.rpgleinc
│ │ ├── projects.ts
│ │ └── include_mismatch_fix
│ │ │ ├── QDDSSRC
│ │ │ └── ARTICLE.PF
│ │ │ └── QPROTOSRC
│ │ │ └── ARTICLE.RPGLE
│ ├── setup.ts
│ ├── cl.test.ts
│ ├── utils.test.ts
│ ├── dclcase.test.ts
│ ├── bobLongNames.test.ts
│ ├── assume_pgms_copy.test.ts
│ ├── sqlReferenceWith.test.ts
│ ├── sqlReference.test.ts
│ ├── cldclf.test.ts
│ ├── mixedCaseExport.test.ts
│ ├── includeMismatchFix.test.ts
│ ├── sqlLongNames.test.ts
│ ├── bobWithExistingFiles.test.ts
│ ├── overrideObjRef.test.ts
│ ├── multiModule.test.ts
│ ├── autofix2.test.ts
│ └── multiModule2.test.ts
├── .gitignore
├── .npmignore
├── vitest.config.ts
├── tsconfig.json
├── todo.md
├── .vscode
│ └── launch.json
├── package.json
├── webpack.config.js
└── readme.md
├── vs
├── icon.png
├── .gitignore
├── .eslintignore
├── tsconfig.base.json
├── .vscodeignore
├── jsconfig.json
├── .vscode
│ ├── settings.json
│ ├── extensions.json
│ ├── tasks.json
│ └── launch.json
├── client
│ ├── src
│ │ ├── views
│ │ │ ├── utils.ts
│ │ │ ├── projectExplorer
│ │ │ │ ├── noticeTreeItem.ts
│ │ │ │ ├── sourceOrbitTreeItem.ts
│ │ │ │ └── ileObjectTreeItem.ts
│ │ │ └── impactView
│ │ │ │ ├── ileImpactedObjectTreeItem.ts
│ │ │ │ └── index.ts
│ │ ├── environmentManager.ts
│ │ ├── api.ts
│ │ ├── gitEventHandler.ts
│ │ ├── ProjectExplorer.ts
│ │ ├── git
│ │ │ └── index.ts
│ │ └── tasks.ts
│ ├── tsconfig.json
│ ├── package.json
│ └── webpack.config.js
├── server
│ ├── tsconfig.json
│ ├── package.json
│ ├── src
│ │ ├── readFileSystem.ts
│ │ ├── requests.ts
│ │ ├── server.ts
│ │ └── fileSystemListener.ts
│ └── webpack.config.js
├── tsconfig.json
├── .eslintrc.js
├── shared.webpack.config.js
└── README.md
├── .gitmodules
├── sourceorbit.code-workspace
└── .github
└── workflows
├── test.yaml
├── webpack.yaml
└── release.yaml
/docs/.nojekyll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.vsix
3 |
4 | testData
5 |
--------------------------------------------------------------------------------
/cli/src/extensions.ts:
--------------------------------------------------------------------------------
1 |
2 | export const referencesFileName = `.objrefs`;
--------------------------------------------------------------------------------
/cli/test/fixtures/pseudo/qobjs/Rules.mk:
--------------------------------------------------------------------------------
1 | MYTHING.DTAARA:text=Hello world
--------------------------------------------------------------------------------
/vs/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IBM/sourceorbit/HEAD/vs/icon.png
--------------------------------------------------------------------------------
/vs/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | node_modules
3 | client/server
4 | .vscode-test
5 | .DS_Store
6 | *.vsix
--------------------------------------------------------------------------------
/cli/test/fixtures/cldclf/apgm.pgm.clle:
--------------------------------------------------------------------------------
1 | PGM
2 | DCLF FILE(*LIBL/DEPARTMENT) OPNID(SAVRSTLIB)
3 | ENDPGM
--------------------------------------------------------------------------------
/cli/test/fixtures/override_objref/.objrefs:
--------------------------------------------------------------------------------
1 | # cool comment
2 |
3 | SAMREF.FILE
4 |
5 | # other comment
--------------------------------------------------------------------------------
/cli/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | .DS_Store
4 |
5 | !from_qsys
6 | !include_fix
7 | !company_system
--------------------------------------------------------------------------------
/cli/test/fixtures/dds_deps_with_refs/.objrefs:
--------------------------------------------------------------------------------
1 | # cool comment
2 |
3 | SAMREF.FILE
4 |
5 | # other comment
--------------------------------------------------------------------------------
/cli/test/fixtures/pseudo/qobjs/mything.dtaara:
--------------------------------------------------------------------------------
1 | CRTDTAARA DTARA(MYTHING) TYPE(*CHAR) LEN(15) VALUE('HELLO')
--------------------------------------------------------------------------------
/docs/assets/Extension_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IBM/sourceorbit/HEAD/docs/assets/Extension_01.png
--------------------------------------------------------------------------------
/docs/assets/Extension_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IBM/sourceorbit/HEAD/docs/assets/Extension_02.png
--------------------------------------------------------------------------------
/docs/assets/Extension_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IBM/sourceorbit/HEAD/docs/assets/Extension_03.png
--------------------------------------------------------------------------------
/docs/assets/Migrating_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IBM/sourceorbit/HEAD/docs/assets/Migrating_01.png
--------------------------------------------------------------------------------
/docs/assets/Installation_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IBM/sourceorbit/HEAD/docs/assets/Installation_03.png
--------------------------------------------------------------------------------
/cli/.npmignore:
--------------------------------------------------------------------------------
1 | index.ts
2 | tsconfig.json
3 | webpack.config.js
4 | test
5 | src
6 | !dist/src
7 | node_modules
8 | .vscode
--------------------------------------------------------------------------------
/cli/test/fixtures/assume_pgms_copy/qrpgleref/scooby.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | dcl-c myconstant 'Hello world';
4 |
5 | return;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qsrvsrc/banking.bnd:
--------------------------------------------------------------------------------
1 | STRPGMEXP PGMLVL(*CURRENT)
2 | EXPORT SYMBOL(DOUBLEIT)
3 | ENDPGMEXP
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qsrvsrc/utils.bnd:
--------------------------------------------------------------------------------
1 | strpgmexp pgmlvl(*current)
2 | export symbol('TOLOWER')
3 | endpgmexp
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qddssrc/Rules.mk:
--------------------------------------------------------------------------------
1 | DEPTS.FILE: depts.dspf
2 | EMPS.FILE: emps.dspf
3 | NEMP.FILE: nemp.dspf
--------------------------------------------------------------------------------
/cli/test/fixtures/metadata/qobjs/mything.dtaara:
--------------------------------------------------------------------------------
1 | CRTDTAARA DTARA(MYTHING) TYPE(*CHAR) LEN(15) VALUE('HELLO') TEXT('MY DATA AREA')
--------------------------------------------------------------------------------
/cli/test/fixtures/pseudo/qobjs/.ibmi.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.0.1",
3 | "build": {
4 | "tgtCcsid": "37"
5 | }
6 | }
--------------------------------------------------------------------------------
/vs/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/**
2 | client/node_modules/**
3 | client/out/**
4 | server/node_modules/**
5 | server/out/**
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qsrvsrc/banking.bnd:
--------------------------------------------------------------------------------
1 | STRPGMEXP PGMLVL(*CURRENT)
2 | EXPORT SYMBOL(DOUBLEIT)
3 | ENDPGMEXP
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qsrvsrc/utils.bnd:
--------------------------------------------------------------------------------
1 | STRPGMEXP PGMLVL(*CURRENT)
2 | EXPORT SYMBOL('TOLOWER')
3 | ENDPGMEXP
--------------------------------------------------------------------------------
/cli/test/fixtures/pseudo/qrpglesrc/.ibmi.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.0.1",
3 | "build": {
4 | "tgtCcsid": "273"
5 | }
6 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/pseudo/qrpglesrc/other.pgm.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | dcl-f mstdsp workstn usropn;
4 |
5 | thearea = 'Hello world';
6 |
7 | return;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qrpgleref/utils.rpgleinc:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | dcl-pr ToLower char(50) extproc;
4 | inputString char(50) value;
5 | end-pr;
--------------------------------------------------------------------------------
/cli/test/fixtures/metadata/qobjs/.ibmi.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.0.1",
3 | "build": {
4 | "objlib": "OTHER",
5 | "tgtCcsid": "37"
6 | }
7 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/assume_pgms_copy/qrpglesrc/hello.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | /copy qrpgleref,scooby
4 |
5 | dsply myconstant;
6 |
7 | *inlr = *on;
8 | return;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qrpgleref/utils.rpgleinc:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | dcl-pr ToLower char(50) extproc;
4 | inputString char(50) value;
5 | end-pr;
--------------------------------------------------------------------------------
/cli/test/fixtures/metadata/qrpglesrc/tester.pgm.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | dcl-s thearea char(15) dtaara('MYTHING');
4 |
5 | thearea = 'Hello world';
6 |
7 | return;
--------------------------------------------------------------------------------
/cli/test/fixtures/pseudo/qrpglesrc/tester.pgm.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | dcl-s thearea char(15) dtaara('MYTHING');
4 |
5 | thearea = 'Hello world';
6 |
7 | return;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qsqlsrc/showemps.sql:
--------------------------------------------------------------------------------
1 | create or replace procedure SHOWEMPS (IN dept char(3))
2 | LANGUAGE RPGLE
3 | EXTERNAL NAME EMPLOYEES GENERAL;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qsqlsrc/showemps.sql:
--------------------------------------------------------------------------------
1 | create or replace procedure SHOWEMPS (IN dept char(3))
2 | LANGUAGE RPGLE
3 | EXTERNAL NAME EMPLOYEES GENERAL;
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "ibmi-company_system-rmake"]
2 | path = ibmi-company_system-rmake
3 | url = https://github.com/worksofliam/ibmi-company_system-rmake.git
4 | ignore = dirty
5 |
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qrpglesrc/empdet.bnd:
--------------------------------------------------------------------------------
1 | STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('V1')
2 | EXPORT SYMBOL('GETEMPLOYEEDETAIL')
3 | EXPORT SYMBOL('GETDEPTDETAIL')
4 | ENDPGMEXP
--------------------------------------------------------------------------------
/cli/test/fixtures/pseudo/qrpglesrc/Rules.mk:
--------------------------------------------------------------------------------
1 | TESTER.PGM: tester.pgm.rpgle MYTHING.DTAARA NOEXIST.PGM
2 | TESTER.PGM: text = My program
3 |
4 | # Other assignment
5 | TESTER.PGM: bnddir:=MYBND
--------------------------------------------------------------------------------
/vs/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "noImplicitAny": true,
4 | "noUnusedParameters": true,
5 | "strict": true,
6 | "allowJs": true,
7 | "types": ["node"]
8 | }
9 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/auto_rename1/src/CBKOPTIMIZ.rpgle:
--------------------------------------------------------------------------------
1 | * Level optimisation FULL
2 | * The most efficient code is generated.
3 | * Translation time is the longest.
4 | H OPTIMIZE(*FULL)
5 |
--------------------------------------------------------------------------------
/vs/.vscodeignore:
--------------------------------------------------------------------------------
1 | .github/**
2 | assets/**
3 | **/node_modules
4 | node_modules
5 | scripts
6 | .vscode/**
7 | .gitignore
8 | **/jsconfig.json
9 | **/*.map
10 | **/.eslintrc.json
11 | tests
12 | server
13 | client
--------------------------------------------------------------------------------
/cli/vitest.config.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import { defineConfig } from 'vite'
3 |
4 | export default defineConfig({
5 | test: {
6 | // ... Specify options here.
7 | globalSetup: [`test/setup.ts`],
8 | },
9 | })
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qsqlsrc/getDouble.sql:
--------------------------------------------------------------------------------
1 | Create function getDouble (inputNumber decimal(11, 2))
2 | returns decimal(11, 2)
3 | language rpgle
4 | external name BANKING(doubleIt)
5 | parameter style general;
--------------------------------------------------------------------------------
/docs/pages/general/structure.md:
--------------------------------------------------------------------------------
1 | # Project Structure
2 |
3 | See the documentation [here](https://codefori.github.io/docs/developing/local/structure) on project structure in the Code for IBM i documentation, as Source Orbit follows that structure.
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qsqlsrc/getDouble.sql:
--------------------------------------------------------------------------------
1 | Create function getDouble (inputNumber decimal(11, 2))
2 | returns decimal(11, 2)
3 | language rpgle
4 | external name BANKING(doubleIt)
5 | parameter style general;
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qddssrc/actions.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Run SQL stuff",
4 | "environment": "ile",
5 | "extensions": [
6 | "sql", "table"
7 | ],
8 | "command": "RUNSQLSTM SRCSTMF('&RELATIVEPATH')"
9 | }
10 | ]
--------------------------------------------------------------------------------
/vs/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "checkJs": true, /* Typecheck .js files. */
6 | "lib": [
7 | "es6"
8 | ]
9 | },
10 | "exclude": [
11 | "node_modules"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/cli/test/fixtures/sql_ref_with/sqlwithpgm.pgm.sqlrpgle:
--------------------------------------------------------------------------------
1 | **FREE
2 |
3 | exec sql declare c1 cursor for
4 | with temp as (
5 | select
6 | field1,
7 | field2
8 | from table1
9 | )
10 | Select * from temp;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qrpglesrc/banking.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt nomain;
4 |
5 | dcl-proc doubleIt export;
6 | dcl-pi *n packed(11:2);
7 | inputNum packed(11:2) value;
8 | end-pi;
9 |
10 | return inputNum * 2;
11 | end-proc;
12 |
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qrpglesrc/banking.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt nomain;
4 |
5 | dcl-proc doubleIt export;
6 | dcl-pi *n packed(11:2);
7 | inputNum packed(11:2) value;
8 | end-pi;
9 |
10 | return inputNum * 2;
11 | end-proc;
12 |
--------------------------------------------------------------------------------
/cli/test/fixtures/multi_module_two/rpgle/runner.pgm.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | dcl-pr createCustomer int(10) extproc('CREATECUSTOMER');
4 | type char(1) const;
5 | end-pr;
6 |
7 | ctl-opt dftactgrp(*no);
8 |
9 | createCustomer('1');
10 | createCustomer('2');
11 |
12 | return;
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qtestsrc/testing.json:
--------------------------------------------------------------------------------
1 | {
2 | "RPGUnit": {
3 | "RUCRTRPG": {
4 | "tgtCcsid": 37,
5 | "dbgView": "*SOURCE",
6 | "cOption": [
7 | "*EVENTF"
8 | ]
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/vs/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.insertSpaces": false,
3 | "typescript.tsc.autoDetect": "off",
4 | "typescript.preferences.quoteStyle": "single",
5 | "editor.codeActionsOnSave": {
6 | "source.organizeImports": "always",
7 | "source.fixAll.eslint": "explicit"
8 | }
9 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/mixedCaseExport/qsrvsrc/modexcept.bnd:
--------------------------------------------------------------------------------
1 | strpgmexp signature( 'V2021.02')
2 | export symbol(getRandomMethodA)
3 | export symbol(BigFootLivesInSc)
4 | export symbol(validateCoolness)
5 | endpgmexp
6 |
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qsqlsrc/getTotalSalary.sqludf:
--------------------------------------------------------------------------------
1 | create or replace function getTotalSalary ()
2 | returns decimal(9, 2)
3 | specific GETTOTSAL
4 | begin
5 | declare total decimal(9, 2);
6 |
7 | select sum(salary) into total from employee;
8 |
9 | return total;
10 | end;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qsqlsrc/getTotalSalary.sqludf:
--------------------------------------------------------------------------------
1 | create or replace function getTotalSalary ()
2 | returns decimal(9, 2)
3 | specific GETTOTSAL
4 | begin
5 | declare total decimal(9, 2);
6 |
7 | select sum(salary) into total from employee;
8 |
9 | return total;
10 | end;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qrpglesrc/utils.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt nomain;
4 |
5 | dcl-proc ToLower export;
6 | dcl-pi ToLower char(50);
7 | inputString char(50) value;
8 | end-pi;
9 |
10 | exec sql set :inputString = LOWER(:inputString);
11 |
12 | return inputString;
13 | end-proc;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qrpglesrc/utils.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt nomain;
4 |
5 | dcl-proc ToLower export;
6 | dcl-pi ToLower char(50);
7 | inputString char(50) value;
8 | end-pi;
9 |
10 | exec sql set :inputString = LOWER(:inputString);
11 |
12 | return inputString;
13 | end-proc;
--------------------------------------------------------------------------------
/cli/test/fixtures/from_qsys/qsqlsrc/emp.sql:
--------------------------------------------------------------------------------
1 | -- Employee Master
2 | -- Generated on: 11/03/21 14:32:20
3 | CREATE OR REPLACE TABLE super_long_emp_name (
4 | -- SQL150B 10 REUSEDLT(*NO) in table EMPMST in PAYROLL1 ignored.
5 | COL_A CHAR(1) CCSID 37 NOT NULL DEFAULT '' ,
6 | PRIMARY KEY( COL_A ) );
--------------------------------------------------------------------------------
/vs/client/src/views/utils.ts:
--------------------------------------------------------------------------------
1 |
2 | export const TypeIcons = {
3 | "BNDDIR": "book",
4 | "PGM": "terminal",
5 | "FILE": "database",
6 | "CMD": "window",
7 | "SRVPGM": "symbol-constructor",
8 | "MODULE": "symbol-module",
9 | "DTAARA": "file-text",
10 | "MENU": "menu",
11 | "DTAQ": "list-flat"
12 | };
13 |
14 |
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qrpglesrc/app.bnddir:
--------------------------------------------------------------------------------
1 | /* Have to delete the BNDDIR, or it will always be older than the source */
2 | /* because the CRTBNDDIR will fail the second time and only the ADDBNDDIRE is executed */
3 | !DLTOBJ OBJ(&O/&N) OBJTYPE(*BNDDIR)
4 | CRTBNDDIR BNDDIR(&O/&N)
5 | ADDBNDDIRE BNDDIR(&O/&N) OBJ((*LIBL/EMPDET *SRVPGM))
--------------------------------------------------------------------------------
/cli/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "ES2019",
5 | "noImplicitAny": false,
6 | "noUnusedParameters": false,
7 | "strict": false,
8 | "allowJs": true,
9 | "outDir": "./dist",
10 | "esModuleInterop": true,
11 | "sourceMap": true,
12 | "declaration": true,
13 | },
14 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/from_qsys/qsqlsrc/dept.sql:
--------------------------------------------------------------------------------
1 | -- Employee Master
2 | -- Generated on: 11/03/21 14:32:20
3 | CREATE OR REPLACE TABLE super_long_dept_name FOR SYSTEM NAME DEPT (
4 | -- SQL150B 10 REUSEDLT(*NO) in table EMPMST in PAYROLL1 ignored.
5 | COL_B CHAR(1) CCSID 37 NOT NULL DEFAULT '' ,
6 | PRIMARY KEY( COL_B ) );
--------------------------------------------------------------------------------
/vs/client/src/environmentManager.ts:
--------------------------------------------------------------------------------
1 | export class EnvironmentManager {
2 | /**
3 | * Checks if the extension is running Merlin.
4 | *
5 | * @returns True if running in Merlin and false otherwise.
6 | */
7 | static isInMerlin(): boolean {
8 | const { MACHINE_EXEC_PORT } = process.env;
9 | return MACHINE_EXEC_PORT !== undefined;
10 | }
11 | }
--------------------------------------------------------------------------------
/vs/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4 |
5 | // List of extensions which should be recommended for users of this workspace.
6 | "recommendations": [
7 | "dbaeumer.vscode-eslint"
8 | ]
9 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/multi_module/qrpgleref/utils.rpgleinc:
--------------------------------------------------------------------------------
1 | **FREE
2 |
3 | Dcl-Pr Utils_Lower Char(10) ExtProc;
4 | *N Char(10) Value;
5 | End-Pr;
6 |
7 | Dcl-Pr Utils_Print ExtProc;
8 | Command VARCHAR(512) CONST;
9 | End-Pr;
10 |
11 | Dcl-Pr Utils_Qsh IND ExtProc;
12 | Command VARCHAR(512) CONST;
13 | End-Pr;
14 |
15 | Dcl-Pr Utils_JobType Char(1) ExtProc;
16 | End-Pr;
--------------------------------------------------------------------------------
/vs/client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "module": "commonjs",
5 | "target": "es2020",
6 | "lib": ["es2020"],
7 | "outDir": "out",
8 | "rootDir": "src",
9 | "sourceMap": true,
10 | "skipLibCheck": true
11 | },
12 | "include": ["src"],
13 | "exclude": ["node_modules", ".vscode-test"]
14 | }
15 |
--------------------------------------------------------------------------------
/sourceorbit.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "cli"
5 | },
6 | {
7 | "path": "docs"
8 | },
9 | {
10 | "path": "vs"
11 | }
12 | ],
13 | "extensions": {
14 | "recommendations": ["amodio.tsl-problem-matcher"]
15 | },
16 | "mcp": {
17 | "servers": {
18 | "SO Local": {
19 | "url": "http://localhost:5500"
20 | }
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qrpglesrc/mypgm.pgm.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt dftactgrp(*no);
4 |
5 | /INCLUDE 'qrpgleref/constants.rpgleinc'
6 |
7 | dcl-s mytext char(50);
8 |
9 | Dcl-PR printf Int(10) extproc('printf');
10 | input Pointer value options(*string);
11 | End-PR;
12 |
13 | mytext = 'Hello to all you people';
14 | printf(mytext);
15 |
16 | dsply mytext;
17 |
18 | return;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qrpglesrc/mypgm.pgm.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt dftactgrp(*no);
4 |
5 | /INCLUDE 'qrpgleref/constants.rpgleinc'
6 |
7 | dcl-s mytext char(50);
8 |
9 | Dcl-PR printf Int(10) extproc('printf');
10 | input Pointer value options(*string);
11 | End-PR;
12 |
13 | mytext = 'Hello to all you people';
14 | printf(mytext);
15 |
16 | dsply mytext;
17 |
18 | return;
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qrpglesrc/mypgm.pgm.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt dftactgrp(*no);
4 |
5 | /INCLUDE 'qrpgleref/constants.rpgleinc'
6 |
7 | dcl-s mytext char(50);
8 |
9 | Dcl-PR printf Int(10) extproc('printf');
10 | input Pointer value options(*string);
11 | End-PR;
12 |
13 | mytext = 'Hello to all you people';
14 | printf(mytext);
15 |
16 | dsply mytext;
17 |
18 | return;
--------------------------------------------------------------------------------
/cli/test/fixtures/from_qsys/qprotosrc/errortable.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 | // This contains global constants, variables and prototypes
3 | // for the Payroll Maintainance app
4 |
5 | //
6 | // Compile time array containing error descriptions.
7 | Dcl-S ERR Char(50) DIM(10) CTDATA PERRCD(1);
8 |
9 | Dcl-C INVALID_MAINTENANCE_SELECTION 1;
10 | Dcl-C INVALID_ACTION_CODE 4;
11 |
12 |
--------------------------------------------------------------------------------
/cli/test/fixtures/dds_deps/PROVIDE1.LF:
--------------------------------------------------------------------------------
1 | *%METADATA *
2 | * %TEXT Provider file *
3 | *%EMETADATA *
4 | UNIQUE
5 | R FPROV PFILE(PROVIDER)
6 | K PRID
7 |
--------------------------------------------------------------------------------
/cli/test/fixtures/include_fix/QRPGLESRC/ERRORTABLE.rpgleinc:
--------------------------------------------------------------------------------
1 | **free
2 | // This contains global constants, variables and prototypes
3 | // for the Payroll Maintainance app
4 |
5 | //
6 | // Compile time array containing error descriptions.
7 | Dcl-S ERR Char(50) DIM(10) CTDATA PERRCD(1);
8 |
9 | Dcl-C INVALID_MAINTENANCE_SELECTION 1;
10 | Dcl-C INVALID_ACTION_CODE 4;
11 |
12 |
--------------------------------------------------------------------------------
/cli/src/targets/languages/cmd.ts:
--------------------------------------------------------------------------------
1 | import { FileOptions, ILEObject, Targets } from "..";
2 | import { ExtensionMap } from "../languages";
3 |
4 | export const cmdExtensions = [`cmd`];
5 | export const cmdObjects: ExtensionMap = {
6 | cmd: `CMD`
7 | }
8 |
9 | export async function cmdTargetCallback(targets: Targets, localPath: string, content: string, ileObject: ILEObject) {
10 | // Do nothing!
11 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qrpglesrc/mypgm.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt dftactgrp(*no);
4 |
5 | /INCLUDE 'qrpgleref/constants.rpgleinc'
6 |
7 | dcl-s mytext char(50);
8 |
9 | Dcl-PR printf Int(10) extproc('printf');
10 | input Pointer value options(*string);
11 | End-PR;
12 |
13 | mytext = 'Hello to all you people';
14 | printf(mytext);
15 |
16 | dsply mytext;
17 |
18 | return;
--------------------------------------------------------------------------------
/cli/test/fixtures/dds_deps_with_refs/PROVIDE1.LF:
--------------------------------------------------------------------------------
1 | *%METADATA *
2 | * %TEXT Provider file *
3 | *%EMETADATA *
4 | UNIQUE
5 | R FPROV PFILE(PROVIDER)
6 | K PRID
7 |
--------------------------------------------------------------------------------
/cli/test/fixtures/override_objref/PROVIDE1.LF:
--------------------------------------------------------------------------------
1 | *%METADATA *
2 | * %TEXT Provider file *
3 | *%EMETADATA *
4 | UNIQUE
5 | R FPROV PFILE(PROVIDER)
6 | K PRID
7 |
--------------------------------------------------------------------------------
/cli/test/fixtures/sql_references/qddssrc/stock.table:
--------------------------------------------------------------------------------
1 | --%METADATA *
2 | -- %TEXT Stock File *
3 | --%EMETADATA *
4 |
5 | CREATE OR REPLACE TABLE STOCK
6 | (PRDKEY CHAR(6) NOT NULL,
7 | PRDNAM CHAR(12) NOT NULL,
8 | PRIMARY KEY (EMPNO));
9 |
--------------------------------------------------------------------------------
/cli/test/fixtures/sql_references/qrpglesrc/sqlrefpgm.pgm.sqlrpgle:
--------------------------------------------------------------------------------
1 | **FREE
2 | Ctl-Opt Main(SQLREFPGM) dftactgrp(*no) option(*srcstmt);
3 |
4 | dcl-pr SQLREFPGM extpgm('SQLREFPGM');
5 | end-pr;
6 |
7 |
8 | Dcl-Proc SQLREFPGM;
9 | Dcl-Pi *N;
10 | End-Pi;
11 | DCL-S CNT packed(5);
12 | EXEC SQL SELECT COUNT(1) INTO :CNT FROM STOCK;
13 | DSPLY %CHAR('STOCK: ' + %CHAR(CNT));
14 | RETURN;
15 | End-Proc;
--------------------------------------------------------------------------------
/vs/server/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "target": "es2020",
5 | "lib": ["es2020"],
6 | "module": "commonjs",
7 | "moduleResolution": "node",
8 | "sourceMap": true,
9 | "strict": true,
10 | "outDir": "out",
11 | "rootDir": "src",
12 | "esModuleInterop": true
13 | },
14 | "include": ["src"],
15 | "exclude": ["node_modules", ".vscode-test"]
16 | }
17 |
--------------------------------------------------------------------------------
/cli/test/setup.ts:
--------------------------------------------------------------------------------
1 | import type { TestProject } from "vitest/node";
2 | import { getAllFixtures, setupFixture } from "./fixtures/projects";
3 |
4 | export async function setup(project: TestProject) {
5 | console.log(`Setting up project....`);
6 |
7 | console.table(getAllFixtures());
8 |
9 | const fixtures = getAllFixtures();
10 | for (const fixture of fixtures) {
11 | let proj = setupFixture(fixture);
12 | proj.copy();
13 | }
14 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/.vscode/actions.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Create an RPG program",
4 | "environment": "ile",
5 | "extensions": [
6 | "rpgle"
7 | ],
8 | "command": "CRTBNDRPG NAME(&NAME) THEPARM('&RELATIVEPATH')"
9 | },
10 | {
11 | "name": "Global run SQL",
12 | "environment": "ile",
13 | "extensions": [
14 | "sql"
15 | ],
16 | "command": "RUNSQL SRCSTMF('&RELATIVEPATH')"
17 | }
18 | ]
--------------------------------------------------------------------------------
/vs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es2020",
5 | "moduleResolution": "node",
6 | "lib": ["es2020"],
7 | "outDir": "out",
8 | "rootDir": "src",
9 | "sourceMap": true,
10 | "allowJs": true,
11 | },
12 | "include": [
13 | "src"
14 | ],
15 | "exclude": [
16 | "node_modules",
17 | ".vscode-test"
18 | ],
19 | "references": [
20 | { "path": "./client" },
21 | { "path": "./server" }
22 | ]
23 | }
--------------------------------------------------------------------------------
/vs/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vscode-sourceorbit-server",
3 | "description": "Server",
4 | "version": "1.0.1",
5 | "author": "IBM",
6 | "license": "MIT",
7 | "engines": {
8 | "node": "*"
9 | },
10 | "dependencies": {
11 | "@ibm/sourceorbit": "file:../../cli",
12 | "glob": "^7.2.0",
13 | "vscode-languageserver": "^8.1.0",
14 | "vscode-languageserver-textdocument": "^1.0.8",
15 | "vscode-uri": "^3.0.7"
16 | },
17 | "scripts": {},
18 | "devDependencies": {
19 | "@types/glob": "^8.1.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/cli/src/targets/languages/nosrc.ts:
--------------------------------------------------------------------------------
1 | import { Targets, FileOptions, ILEObject } from "..";
2 | import { ExtensionMap } from "../languages";
3 |
4 | export const noSourceObjects = [`dtaara`, `mnucmd`, `msgf`, `dtaq`, `bnddir`];
5 | export const noSourceTargetObjects: ExtensionMap = {
6 | dtaara: `DTAARA`,
7 | mnucmd: `CMD`,
8 | msgf: `FILE`,
9 | dtaq: `DTAQ`,
10 | bnddir: `BNDDIR`
11 | }
12 |
13 | export async function noSourceTargetCallback(targets: Targets, localPath: string, content: string, ileObject: ILEObject) {
14 | // Do nothing!
15 | }
--------------------------------------------------------------------------------
/docs/_sidebar.md:
--------------------------------------------------------------------------------
1 | * [Home](/)
2 | * Projects
3 | * [Project Structure](./pages/general/structure.md)
4 | * [Source Code Rules](./pages/general/rules.md)
5 | * [Migrating to Git](./pages/general/migrating.md)
6 | * CLI
7 | * [Overview](./pages/cli/index.md)
8 | * [Installation](./pages/cli/installation.md)
9 | * [Make](./pages/cli/make.md)
10 | * [GitHub Actions](./pages/cli/gha.md)
11 | * VS Code Extension
12 | * [Overview](./pages/extension/index.md)
13 | * [Installation](./pages/extension/installation.md)
14 | * Tutorials
15 | * Coming soon
--------------------------------------------------------------------------------
/vs/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vscode-sourceorbit-client",
3 | "description": "Client",
4 | "author": "IBM",
5 | "license": "MIT",
6 | "version": "1.0.1",
7 | "publisher": "vscode",
8 | "engines": {
9 | "vscode": "^1.75.0"
10 | },
11 | "dependencies": {
12 | "vscode-languageclient": "^8.1.0"
13 | },
14 | "devDependencies": {
15 | "@ibm/sourceorbit": "file:../../cli",
16 | "@ibm/vscode-ibmi-projectexplorer-types": "^1.1.0",
17 | "@types/node": "^20.5.1",
18 | "@types/vscode": "^1.75.1",
19 | "@vscode/test-electron": "^2.2.3"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/cli/test/fixtures/sql_long_names/sql/trans.table:
--------------------------------------------------------------------------------
1 | -- https://www.ibm.com/docs/en/i/7.3?topic=tables-employee-table-employee
2 |
3 | CREATE OR REPLACE TABLE TRANSACTION FOR SYSTEM NAME TRANS
4 | (TRID integer not null GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
5 | TDESC VARCHAR(50) NOT NULL,
6 | TCUS integer NOT NULL, -- reference to customers
7 | TAMT numeric(10,2) NOT NULL default 0,
8 | TWHEN TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
9 | PRIMARY KEY (TRID)) RCDFMT TRANSFMT;
--------------------------------------------------------------------------------
/vs/server/src/readFileSystem.ts:
--------------------------------------------------------------------------------
1 | import ffs from 'fs';
2 | import fs from 'fs/promises';
3 | import { glob } from 'glob';
4 |
5 | export class ReadFileSystem {
6 | async getFiles(cwd: string, globPath: string): Promise {
7 | return glob.sync(globPath, {
8 | cwd,
9 | absolute: true,
10 | nocase: true,
11 | });
12 | }
13 |
14 | readFile(filePath: string): Promise {
15 | return fs.readFile(filePath, { encoding: `utf8` });
16 | }
17 |
18 | async exists(filePath: string): Promise {
19 | return ffs.existsSync(filePath);
20 | }
21 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qrpgleref/empdet.rpgleinc:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | dcl-ds employee_detail_t qualified template;
4 | found ind;
5 | name varchar(50);
6 | netincome packed(9:2);
7 | end-ds;
8 |
9 | dcl-ds department_detail_t qualified template;
10 | found ind;
11 | deptname varchar(50);
12 | location varchar(50);
13 | totalsalaries packed(9:2);
14 | end-ds;
15 |
16 | dcl-pr getDeptDetail like(department_detail_t) extproc('GETDEPTDETAIL');
17 | deptno char(3) const;
18 | end-pr;
19 |
20 | dcl-pr getEmployeeDetail like(employee_detail_t) extproc('GETEMPLOYEEDETAIL');
21 | empno char(6) const;
22 | end-pr;
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qrpgleref/empdet.rpgleinc:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | dcl-ds employee_detail_t qualified template;
4 | found ind;
5 | name varchar(50);
6 | netincome packed(9:2);
7 | end-ds;
8 |
9 | dcl-ds department_detail_t qualified template;
10 | found ind;
11 | deptname varchar(50);
12 | location varchar(50);
13 | totalsalaries packed(9:2);
14 | end-ds;
15 |
16 | dcl-pr getDeptDetail like(department_detail_t) extproc('GETDEPTDETAIL');
17 | deptno char(3) const;
18 | end-pr;
19 |
20 | dcl-pr getEmployeeDetail like(employee_detail_t) extproc('GETEMPLOYEEDETAIL');
21 | empno char(6) const;
22 | end-pr;
--------------------------------------------------------------------------------
/cli/test/fixtures/dclcase/qrpglesrc/apival01s.pgm.rpgle:
--------------------------------------------------------------------------------
1 | **free
2 | //%METADATA *
3 | // %TEXT API main validation procedure (IWS) *
4 | //%EMETADATA *
5 | ///
6 | // @Program APIVAL01S
7 | //
8 | // @Purpose IWS API validation procedures
9 | //
10 | // @author JHEI
11 | // @Date 22 May 2024
12 | //
13 | ///
14 | ctl-opt option(*srcstmt:*nodebugio);
15 | ctl-opt debug(*retval:*constants);
16 | ctl-opt reqprexp(*require);
17 |
18 | // includes
19 | /copy 'apival01s.rpgleinc'
20 |
21 | dsply 'hello';
22 |
23 | return;
--------------------------------------------------------------------------------
/cli/src/readFileSystem.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs/promises';
2 | import ffs from 'fs';
3 | import glob from "glob";
4 | import path from 'path';
5 | import os from 'os';
6 | import { getFiles } from './utils';
7 |
8 | export class ReadFileSystem {
9 | constructor() {}
10 |
11 | async getFiles(cwd: string, globPath, additionalOpts: any = {}): Promise {
12 | return getFiles(cwd, globPath, additionalOpts);
13 | }
14 |
15 | readFile(filePath: string): Promise {
16 | return fs.readFile(filePath, { encoding: `utf8` });
17 | }
18 |
19 | async exists(filePath: string): Promise {
20 | return ffs.existsSync(filePath);
21 | }
22 | }
--------------------------------------------------------------------------------
/vs/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "type": "npm",
6 | "script": "compile",
7 | "group": "build",
8 | "presentation": {
9 | "panel": "dedicated",
10 | "reveal": "never"
11 | },
12 | "problemMatcher": [
13 | "$tsc"
14 | ]
15 | },
16 | {
17 | "type": "npm",
18 | "script": "watch",
19 | "isBackground": true,
20 | "group": {
21 | "kind": "build",
22 | "isDefault": true
23 | },
24 | "presentation": {
25 | "panel": "dedicated",
26 | "reveal": "never"
27 | },
28 | "problemMatcher": [
29 | "$tsc-watch"
30 | ]
31 | }
32 | ]
33 | }
--------------------------------------------------------------------------------
/vs/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /**@type {import('eslint').Linter.Config} */
2 | // eslint-disable-next-line no-undef
3 | module.exports = {
4 | root: true,
5 | parser: '@typescript-eslint/parser',
6 | plugins: [
7 | '@typescript-eslint',
8 | ],
9 | extends: [
10 | 'eslint:recommended',
11 | 'plugin:@typescript-eslint/recommended',
12 | ],
13 | rules: {
14 | 'semi': [2, "always"],
15 | '@typescript-eslint/no-unused-vars': 0,
16 | '@typescript-eslint/no-explicit-any': 0,
17 | '@typescript-eslint/explicit-module-boundary-types': 0,
18 | '@typescript-eslint/no-non-null-assertion': 0,
19 | "@typescript-eslint/no-namespace": 0,
20 | "no-case-declarations": "off",
21 | }
22 | };
--------------------------------------------------------------------------------
/cli/test/fixtures/multi_module/qrpgleref/system.rpgleinc:
--------------------------------------------------------------------------------
1 | **FREE
2 |
3 | Dcl-PR printf_jl Int(10) extproc('Qp0zLprintf');
4 | format Pointer value options(*string);
5 | End-PR;
6 |
7 | Dcl-PR printf Int(10) extproc('printf');
8 | format Pointer value options(*string);
9 | End-PR;
10 |
11 | Dcl-PR QzshSystem Int(10) extproc('QzshSystem');
12 | format Pointer value options(*string);
13 | End-PR;
14 |
15 | Dcl-PR system Int(10) extproc('system');
16 | *N Pointer value options(*string);
17 | End-PR;
18 |
19 | Dcl-PR QCmdExc extpgm('QCMDEXC');
20 | *N Char(1024) options(*varsize) const;
21 | *N Packed(15:5) const;
22 | End-PR;
23 |
24 | dcl-pr getenv pointer extproc('getenv');
25 | *n pointer value options(*string:*trim);
26 | end-pr;
--------------------------------------------------------------------------------
/cli/test/cl.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 | import { fromCl, toCl } from '../src/utils';
3 |
4 | describe(`CL parsing / generating`, () => {
5 | test('can parse & generate correctly', () => {
6 | const input = `CRTSQLRPGI OBJ(SNDBX87/NEWEMP) SRCSTMF('qrpglesrc/newemp.pgm.sqlrpgle') OPTION(*EVENTF) DBGVIEW(*SOURCE) CLOSQLCSR(*ENDMOD) CVTCCSID(*JOB) COMPILEOPT('TGTCCSID(*JOB)') RPGPPOPT(*LVL2)`;
7 |
8 | const { command, parameters } = fromCl(input);
9 |
10 | expect(command).toBe('CRTSQLRPGI');
11 | expect(Object.keys(parameters)).toHaveLength(8);
12 |
13 | expect(parameters[`compileopt`]).toBe(`'TGTCCSID(*JOB)'`);
14 |
15 | const generated = toCl(command, parameters);
16 |
17 | expect(generated).toBe(input);
18 | });
19 | });
--------------------------------------------------------------------------------
/cli/todo.md:
--------------------------------------------------------------------------------
1 | Things to do:
2 |
3 | * ✅ rename project to Source Orbit
4 | * ✅ update readme with new service program understandings
5 | * ✅ Assume binder source is SRVPGM object
6 | * ✅ When service program is built from source, resolve modules based on binder exports matched against module exports
7 | * ✅ Support variables in make build, specifically for multi-module service programs
8 | * Throw warnings when binder source exports is not in sync with exports from found module
9 | * ✅ Create new test case suite based on ibmi-company_system
10 | * Provide sample projects
11 | * Provide CI examples
12 | * Support for `FOR SYSTEM NAME` in SQL
13 | * ✅ Put rename provider into Targets class
14 | * ✅ Put line fixed into Targets class
15 | * ✅ Support passing in multiple seperate files instead of only the glob
--------------------------------------------------------------------------------
/cli/test/fixtures/multi_module/qrpgleref/dataarea.rpgleinc:
--------------------------------------------------------------------------------
1 | **FREE
2 |
3 | // Returned Data Structure
4 | Dcl-DS DSResult_T Qualified Template;
5 | BytesAvail Int(10);
6 | BytesReturned Int(10);
7 | DataType Char(10);
8 | Library Char(10);
9 | RtnLength Int(10);
10 | DecPos Int(10);
11 | Data Char(300);
12 | End-DS;
13 |
14 | // Retrieve Data Area API
15 | Dcl-PR getDataArea ExtPgm('QWCRDTAA');
16 | ReturnVar LikeDS(DSResult_T);
17 | ReturnLen Int(10) Const;
18 | QualDataArea Char(20) Const;
19 | StartPos Int(10) Const;
20 | DataLen Int(10) Const;
21 | ErrorCode Char(300) Options(*VarSize);
22 | End-PR;
23 |
24 | Dcl-Ds Error_T Qualified Template;
25 | Content Char(300);
26 | Code Char(7) Pos(9);
27 | End-Ds;
--------------------------------------------------------------------------------
/vs/client/src/views/projectExplorer/noticeTreeItem.ts:
--------------------------------------------------------------------------------
1 | import { ProjectExplorerTreeItem } from "@ibm/vscode-ibmi-projectexplorer-types/views/projectExplorer/projectExplorerTreeItem";
2 | import { ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
3 | import { ILEObjectTreeItem } from './ileObjectTreeItem';
4 |
5 | export class NoticeTreeItem extends TreeItem implements ProjectExplorerTreeItem {
6 | constructor(public workspaceFolder: WorkspaceFolder, message: string) {
7 | super(message, TreeItemCollapsibleState.None);
8 | this.iconPath = new ThemeIcon(`unverified`);
9 | }
10 |
11 | setCommand(command: string, arg?: string) {
12 | this.command = { command: command, title: ``, arguments: [this.workspaceFolder, arg] };
13 | }
14 |
15 | async getChildren(): Promise {
16 | return [];
17 | }
18 | }
--------------------------------------------------------------------------------
/cli/src/cli.ts:
--------------------------------------------------------------------------------
1 |
2 | export type BuildFiles = "none" | "make" | "bob" | "imd" | "json";
3 |
4 | export let cliSettings = {
5 | cliMode: false,
6 | infoMessages: false,
7 | buildFile: "none" as BuildFiles,
8 | withActions: false,
9 | fixIncludes: false,
10 | autoRename: false,
11 | lookupFiles: undefined as string[]|undefined,
12 | userBranch: ``,
13 | makefileWithChildren: true,
14 | makefileWithParents: false,
15 | makefileWithParentsChildren: false,
16 | assumeSourcesArePrograms: false,
17 | };
18 |
19 | export function infoOut(message: string) {
20 | if (cliSettings.cliMode && cliSettings.infoMessages) console.log(message);
21 | }
22 |
23 | export function warningOut(message: string) {
24 | if (cliSettings.cliMode) console.log(message);
25 | }
26 |
27 | export function error(message: string) {
28 | console.log(`[ERROR] ${message}`);
29 | }
--------------------------------------------------------------------------------
/vs/client/webpack.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable @typescript-eslint/no-var-requires */
3 | /*---------------------------------------------------------------------------------------------
4 | * Copyright (c) Microsoft Corporation. All rights reserved.
5 | * Licensed under the MIT License. See License.txt in the project root for license information.
6 | *--------------------------------------------------------------------------------------------*/
7 |
8 | //@ts-check
9 |
10 | 'use strict';
11 |
12 | const withDefaults = require(`../shared.webpack.config.js`);
13 | const path = require(`path`);
14 |
15 | module.exports = withDefaults({
16 | context: path.join(__dirname),
17 | entry: {
18 | extension: `./src/extension.ts`,
19 | },
20 | output: {
21 | filename: `extension.js`,
22 | path: path.join(__dirname, `..`, `out`)
23 | }
24 | });
--------------------------------------------------------------------------------
/cli/test/fixtures/multi_module_two/sql/customer.table:
--------------------------------------------------------------------------------
1 | -- https://www.ibm.com/docs/en/i/7.3?topic=tables-employee-table-employee
2 |
3 | CREATE OR REPLACE TABLE CUSTOMER
4 | (CUSNO integer not null GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
5 | FIRSTNME VARCHAR(12) NOT NULL,
6 | LASTNAME VARCHAR(15) NOT NULL,
7 | PHONENO CHAR(4) NOT NULL,
8 | CREATED DATE NOT NULL DEFAULT CURRENT_DATE,
9 | ADDR1 VARCHAR(30) NOT NULL,
10 | ADDR2 VARCHAR(30) NOT NULL,
11 | CITY VARCHAR(20) NOT NULL,
12 | STATE CHAR(2) NOT NULL,
13 | ZIP CHAR(5) NOT NULL,
14 | PRIMARY KEY (CUSNO)
15 | ) RCDFMT CUSTFMT;
16 |
17 | ALTER TABLE CUSTOMER
18 | ADD CONSTRAINT NUMBER
19 | CHECK (PHONENO >= '0000' AND PHONENO <= '9998');
20 |
--------------------------------------------------------------------------------
/cli/test/utils.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from "vitest";
2 | import { globalEntryIsValid } from "../src/utils";
3 |
4 | describe(`util tests`, () => {
5 | it(`should pass`, () => {
6 | expect(globalEntryIsValid(`/RPGLEREPL/BND/REPL_CMPL.BND`, `QRPGLEREF/REPL_USR.*`)).toBeFalsy();
7 | expect(globalEntryIsValid(`/RPGLEREPL/REF/REPL_USR.RPGLEINC`, `QRPGLEREF/REPL_USR.*`)).toBeFalsy();
8 | expect(globalEntryIsValid(`/RPGLEREPL/BND/REPL_USR.BND`, `REPL_USR.R*`)).toBeFalsy();
9 | expect(globalEntryIsValid(`/RPGLEREPL/QRPGLEREF/REPL_USR.BND`, `REPL_USR.R*`)).toBeFalsy();
10 |
11 | expect(globalEntryIsValid(`/RPGLEREPL/QRPGLEREF/REPL_USR.RPGLEINC`, `REPL_USR.R*`)).toBeTruthy();
12 | expect(globalEntryIsValid(`/RPGLEREPL/QRPGLEREF/REPL_USR.RPGLEINC`, `QRPGLEREF/REPL_USR.*`)).toBeTruthy();
13 | expect(globalEntryIsValid(`/RPGLEREPL/BND/REPL_USR.BND`, `REPL_USR.*`)).toBeTruthy();
14 | });
15 | });
--------------------------------------------------------------------------------
/vs/client/src/api.ts:
--------------------------------------------------------------------------------
1 | import { commands, ExtensionContext, WorkspaceFolder } from 'vscode';
2 | import { LanguageClientManager } from './languageClientManager';
3 |
4 | /**
5 | * These commands are to be used by other extensions.
6 | */
7 | export namespace SourceOrbitApi {
8 | export function registerCommands(context: ExtensionContext) {
9 | context.subscriptions.push(
10 | commands.registerCommand(`vscode-sourceorbit.autoFix`, (workspaceFolder: WorkspaceFolder, type: "includes" | "renames") => {
11 | if (workspaceFolder && type) {
12 | return LanguageClientManager.fixProject(workspaceFolder, type);
13 | }
14 | }),
15 |
16 | commands.registerCommand(`vscode-sourceorbit.generateBuildFile`, async (workspaceFolder: WorkspaceFolder, type: string) => {
17 | if (workspaceFolder && type) {
18 | await LanguageClientManager.generateBuildFile(workspaceFolder, type);
19 | }
20 | })
21 | );
22 | }
23 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/cldclf/department.table:
--------------------------------------------------------------------------------
1 | --https://www.ibm.com/docs/en/i/7.3?topic=tables-department-table-department
2 |
3 | CREATE OR REPLACE TABLE DEPARTMENT
4 | (DEPTNO CHAR(3) NOT NULL,
5 | DEPTNAME VARCHAR(36) NOT NULL,
6 | MGRNO CHAR(6) NOT NULL,
7 | ADMRDEPT CHAR(3) NOT NULL,
8 | LOCATION CHAR(16) NOT NULL,
9 | PRIMARY KEY (DEPTNO));
10 |
11 | ALTER TABLE DEPARTMENT
12 | ADD FOREIGN KEY ROD (ADMRDEPT)
13 | REFERENCES DEPARTMENT
14 | ON DELETE CASCADE;
15 |
16 | -- Remove circular reference
17 | --ALTER TABLE DEPARTMENT
18 | -- ADD FOREIGN KEY RDE (MGRNO)
19 | -- REFERENCES EMPLOYEE
20 | -- ON DELETE SET NULL;
21 |
22 | -- CREATE UNIQUE INDEX XDEPT1
23 | -- ON DEPARTMENT (DEPTNO);
24 |
25 | -- CREATE INDEX XDEPT2
26 | -- ON DEPARTMENT (MGRNO);
27 |
28 | -- CREATE INDEX XDEPT3
29 | -- ON DEPARTMENT (ADMRDEPT);
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qddssrc/department.table:
--------------------------------------------------------------------------------
1 | --https://www.ibm.com/docs/en/i/7.3?topic=tables-department-table-department
2 |
3 | CREATE OR REPLACE TABLE DEPARTMENT
4 | (DEPTNO CHAR(3) NOT NULL,
5 | DEPTNAME VARCHAR(36) NOT NULL,
6 | MGRNO CHAR(6) NOT NULL,
7 | ADMRDEPT CHAR(3) NOT NULL,
8 | LOCATION CHAR(16) NOT NULL,
9 | PRIMARY KEY (DEPTNO));
10 |
11 | ALTER TABLE DEPARTMENT
12 | ADD FOREIGN KEY ROD (ADMRDEPT)
13 | REFERENCES DEPARTMENT
14 | ON DELETE CASCADE;
15 |
16 | -- Remove circular reference
17 | --ALTER TABLE DEPARTMENT
18 | -- ADD FOREIGN KEY RDE (MGRNO)
19 | -- REFERENCES EMPLOYEE
20 | -- ON DELETE SET NULL;
21 |
22 | -- CREATE UNIQUE INDEX XDEPT1
23 | -- ON DEPARTMENT (DEPTNO);
24 |
25 | -- CREATE INDEX XDEPT2
26 | -- ON DEPARTMENT (MGRNO);
27 |
28 | -- CREATE INDEX XDEPT3
29 | -- ON DEPARTMENT (ADMRDEPT);
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qrpgleref/constants.rpgleinc:
--------------------------------------------------------------------------------
1 | Dcl-C F01 X'31';
2 | Dcl-C F02 X'32';
3 | Dcl-C F03 X'33';
4 | Dcl-C F04 X'34';
5 | Dcl-C F05 X'35';
6 | Dcl-C F06 X'36';
7 | Dcl-C F07 X'37';
8 | Dcl-C F08 X'38';
9 | Dcl-C F09 X'39';
10 | Dcl-C F10 X'3A';
11 | Dcl-C F11 X'3B';
12 | Dcl-C F12 X'3C';
13 | Dcl-C F13 X'B1';
14 | Dcl-C F14 X'B2';
15 | Dcl-C F15 X'B3';
16 | Dcl-C F16 X'B4';
17 | Dcl-C F17 X'B5';
18 | Dcl-C F18 X'B6';
19 | Dcl-C F19 X'B7';
20 | Dcl-C F20 X'B8';
21 | Dcl-C F21 X'B9';
22 | Dcl-C F22 X'BA';
23 | Dcl-C F24 X'BC';
24 | Dcl-C ENTER X'F1';
25 | Dcl-C HELP X'F3';
26 | Dcl-C PRINT X'F6';
27 |
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qrpgleref/constants.rpgleinc:
--------------------------------------------------------------------------------
1 | Dcl-C F01 X'31';
2 | Dcl-C F02 X'32';
3 | Dcl-C F03 X'33';
4 | Dcl-C F04 X'34';
5 | Dcl-C F05 X'35';
6 | Dcl-C F06 X'36';
7 | Dcl-C F07 X'37';
8 | Dcl-C F08 X'38';
9 | Dcl-C F09 X'39';
10 | Dcl-C F10 X'3A';
11 | Dcl-C F11 X'3B';
12 | Dcl-C F12 X'3C';
13 | Dcl-C F13 X'B1';
14 | Dcl-C F14 X'B2';
15 | Dcl-C F15 X'B3';
16 | Dcl-C F16 X'B4';
17 | Dcl-C F17 X'B5';
18 | Dcl-C F18 X'B6';
19 | Dcl-C F19 X'B7';
20 | Dcl-C F20 X'B8';
21 | Dcl-C F21 X'B9';
22 | Dcl-C F22 X'BA';
23 | Dcl-C F24 X'BC';
24 | Dcl-C ENTER X'F1';
25 | Dcl-C HELP X'F3';
26 | Dcl-C PRINT X'F6';
27 |
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qrpgleref/constants.rpgleinc:
--------------------------------------------------------------------------------
1 | Dcl-C F01 X'31';
2 | Dcl-C F02 X'32';
3 | Dcl-C F03 X'33';
4 | Dcl-C F04 X'34';
5 | Dcl-C F05 X'35';
6 | Dcl-C F06 X'36';
7 | Dcl-C F07 X'37';
8 | Dcl-C F08 X'38';
9 | Dcl-C F09 X'39';
10 | Dcl-C F10 X'3A';
11 | Dcl-C F11 X'3B';
12 | Dcl-C F12 X'3C';
13 | Dcl-C F13 X'B1';
14 | Dcl-C F14 X'B2';
15 | Dcl-C F15 X'B3';
16 | Dcl-C F16 X'B4';
17 | Dcl-C F17 X'B5';
18 | Dcl-C F18 X'B6';
19 | Dcl-C F19 X'B7';
20 | Dcl-C F20 X'B8';
21 | Dcl-C F21 X'B9';
22 | Dcl-C F22 X'BA';
23 | Dcl-C F24 X'BC';
24 | Dcl-C ENTER X'F1';
25 | Dcl-C HELP X'F3';
26 | Dcl-C PRINT X'F6';
27 |
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qsqlsrc/department.table:
--------------------------------------------------------------------------------
1 | --https://www.ibm.com/docs/en/i/7.3?topic=tables-department-table-department
2 |
3 | CREATE OR REPLACE TABLE DEPARTMENT
4 | (DEPTNO CHAR(3) NOT NULL,
5 | DEPTNAME VARCHAR(36) NOT NULL,
6 | MGRNO CHAR(6) NOT NULL,
7 | ADMRDEPT CHAR(3) NOT NULL,
8 | LOCATION CHAR(16) NOT NULL,
9 | PRIMARY KEY (DEPTNO));
10 |
11 | ALTER TABLE DEPARTMENT
12 | ADD FOREIGN KEY ROD (ADMRDEPT)
13 | REFERENCES DEPARTMENT
14 | ON DELETE CASCADE;
15 |
16 | -- Remove circular reference
17 | --ALTER TABLE DEPARTMENT
18 | -- ADD FOREIGN KEY RDE (MGRNO)
19 | -- REFERENCES EMPLOYEE
20 | -- ON DELETE SET NULL;
21 |
22 | -- CREATE UNIQUE INDEX XDEPT1
23 | -- ON DEPARTMENT (DEPTNO);
24 |
25 | -- CREATE INDEX XDEPT2
26 | -- ON DEPARTMENT (MGRNO);
27 |
28 | -- CREATE INDEX XDEPT3
29 | -- ON DEPARTMENT (ADMRDEPT);
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qrpgleref/constants.rpgleinc:
--------------------------------------------------------------------------------
1 | Dcl-C F01 X'31';
2 | Dcl-C F02 X'32';
3 | Dcl-C F03 X'33';
4 | Dcl-C F04 X'34';
5 | Dcl-C F05 X'35';
6 | Dcl-C F06 X'36';
7 | Dcl-C F07 X'37';
8 | Dcl-C F08 X'38';
9 | Dcl-C F09 X'39';
10 | Dcl-C F10 X'3A';
11 | Dcl-C F11 X'3B';
12 | Dcl-C F12 X'3C';
13 | Dcl-C F13 X'B1';
14 | Dcl-C F14 X'B2';
15 | Dcl-C F15 X'B3';
16 | Dcl-C F16 X'B4';
17 | Dcl-C F17 X'B5';
18 | Dcl-C F18 X'B6';
19 | Dcl-C F19 X'B7';
20 | Dcl-C F20 X'B8';
21 | Dcl-C F21 X'B9';
22 | Dcl-C F22 X'BA';
23 | Dcl-C F24 X'BC';
24 | Dcl-C ENTER X'F1';
25 | Dcl-C HELP X'F3';
26 | Dcl-C PRINT X'F6';
27 |
--------------------------------------------------------------------------------
/cli/test/dclcase.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, test } from "vitest";
2 | import { setupFixture } from "./fixtures/projects";
3 |
4 | import { Targets } from '../src/targets'
5 | import { ReadFileSystem } from "../src/readFileSystem";
6 |
7 |
8 | test(`Check that dclcase is being imported correctly`, async () => {
9 | const project = setupFixture(`dclcase`);
10 |
11 | // First step is to rename the files
12 |
13 | const fs = new ReadFileSystem();
14 | const targets = new Targets(project.cwd, fs);
15 | targets.setSuggestions({renames: true});
16 |
17 | project.setup();
18 | await targets.loadProject();
19 |
20 | const pgmObject = targets.getTarget({systemName: `APIVAL01S`, type: `PGM`});
21 |
22 | expect(pgmObject).toBeDefined();
23 | expect(pgmObject.systemName).toBe(`APIVAL01S`);
24 | expect(pgmObject.type).toBe(`PGM`);
25 | expect(pgmObject.imports.length).toBe(1);
26 | expect(pgmObject.imports[0]).toBe(`APIVAL01S_iws_validate`);
27 |
28 |
29 | targets.resolveBinder();
30 | });
31 |
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qddssrc/department.table:
--------------------------------------------------------------------------------
1 | --https://www.ibm.com/docs/en/i/7.3?topic=tables-department-table-department
2 |
3 | CREATE OR REPLACE TABLE long_department_name for system name department
4 | (DEPTNO CHAR(3) NOT NULL,
5 | DEPTNAME VARCHAR(36) NOT NULL,
6 | MGRNO CHAR(6) ,
7 | ADMRDEPT CHAR(3) NOT NULL,
8 | LOCATION CHAR(16),
9 | PRIMARY KEY (DEPTNO));
10 |
11 | ALTER TABLE DEPARTMENT
12 | ADD FOREIGN KEY ROD (ADMRDEPT)
13 | REFERENCES DEPARTMENT
14 | ON DELETE CASCADE;
15 |
16 | -- Remove circular reference
17 | --ALTER TABLE DEPARTMENT
18 | -- ADD FOREIGN KEY RDE (MGRNO)
19 | -- REFERENCES EMPLOYEE
20 | -- ON DELETE SET NULL;
21 |
22 | -- CREATE UNIQUE INDEX XDEPT1
23 | -- ON DEPARTMENT (DEPTNO);
24 |
25 | -- CREATE INDEX XDEPT2
26 | -- ON DEPARTMENT (MGRNO);
27 |
28 | -- CREATE INDEX XDEPT3
29 | -- ON DEPARTMENT (ADMRDEPT);
--------------------------------------------------------------------------------
/docs/pages/cli/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | This page describes how you can install the [@ibm/sourceorbit](https://www.npmjs.com/package/@ibm/sourceorbit) CLI tool from NPM.
4 |
5 | ## Most Platforms
6 |
7 | 1. Install Source Orbit globally
8 | ```sh
9 | npm i -g @ibm/sourceorbit
10 | ```
11 |
12 | 2. Use `so`
13 |
14 | > [!TIP]
15 | > We recommend Node.js 18+.
16 |
17 | ## IBM i
18 |
19 | 1. Install Node.js via `yum` and/or use `update-alternatives` to set the Node.js version.
20 | ```sh
21 | yum install nodejsxx
22 | ```
23 | ```sh
24 | update-alternatives --set node /QOpenSys/pkgs/lib/nodejs18/bin/node
25 | ```
26 |
27 | 2. Install Source Orbit globally on to the IBM i
28 | ```sh
29 | npm i -g @ibm/sourceorbit
30 | ```
31 |
32 | 3. Update the `PATH` environment variable to include the `npm` binary directory for installed CLI packages
33 | * `PATH=/QOpenSys/pkgs/lib/nodejs18/bin:$PATH`
34 | * Put in `.bash_profile` for CLI usage, put in `.bashrc` for Code for IBM i usage
35 |
36 | 4. Use `so`
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qddssrc/department.table:
--------------------------------------------------------------------------------
1 | --https://www.ibm.com/docs/en/i/7.3?topic=tables-department-table-department
2 |
3 | CREATE OR REPLACE TABLE long_department_name for system name department
4 | (DEPTNO CHAR(3) NOT NULL,
5 | DEPTNAME VARCHAR(36) NOT NULL,
6 | MGRNO CHAR(6) ,
7 | ADMRDEPT CHAR(3) NOT NULL,
8 | LOCATION CHAR(16),
9 | PRIMARY KEY (DEPTNO));
10 |
11 | ALTER TABLE DEPARTMENT
12 | ADD FOREIGN KEY ROD (ADMRDEPT)
13 | REFERENCES DEPARTMENT
14 | ON DELETE CASCADE;
15 |
16 | -- Remove circular reference
17 | --ALTER TABLE DEPARTMENT
18 | -- ADD FOREIGN KEY RDE (MGRNO)
19 | -- REFERENCES EMPLOYEE
20 | -- ON DELETE SET NULL;
21 |
22 | -- CREATE UNIQUE INDEX XDEPT1
23 | -- ON DEPARTMENT (DEPTNO);
24 |
25 | -- CREATE INDEX XDEPT2
26 | -- ON DEPARTMENT (MGRNO);
27 |
28 | -- CREATE INDEX XDEPT3
29 | -- ON DEPARTMENT (ADMRDEPT);
--------------------------------------------------------------------------------
/.github/workflows/test.yaml:
--------------------------------------------------------------------------------
1 | name: Test with Vitest
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | push:
7 | branches: ["main"]
8 | paths:
9 | - 'cli/**'
10 |
11 | pull_request:
12 | branches: ["main"]
13 | paths:
14 | - 'cli/**'
15 |
16 | jobs:
17 | build:
18 | strategy:
19 | matrix:
20 | os: [macos-latest, ubuntu-latest, windows-latest]
21 | node-version: [18.x]
22 |
23 | runs-on: ${{ matrix.os }}
24 | defaults:
25 | run:
26 | working-directory: ./cli
27 | steps:
28 | - name: Checkout
29 | uses: actions/checkout@v3
30 |
31 | - name: Use Node.js ${{ matrix.node-version }}
32 | uses: actions/setup-node@v3
33 | with:
34 | node-version: ${{ matrix.node-version }}
35 |
36 | - name: Install NPM Dependencies
37 | run: npm install
38 |
39 | - name: Run Test
40 | run: npm run test
41 |
42 | - name: Pack
43 | run: |
44 | npm run webpack
45 | npm pack
46 |
--------------------------------------------------------------------------------
/cli/test/bobLongNames.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import { setupFixture } from './fixtures/projects';
5 | import { ReadFileSystem } from '../src/readFileSystem';
6 |
7 | const fs = new ReadFileSystem();
8 |
9 | describe(`long name test`, () => {
10 | const project = setupFixture(`bob_long_names`);
11 |
12 | const targets = new Targets(project.cwd, fs);
13 | targets.setSuggestions({ renames: true, includes: true })
14 |
15 | beforeAll(async () => {
16 | project.setup();
17 | await targets.loadProject();
18 |
19 | expect(targets.getTargets().length).toBeGreaterThan(0);
20 | targets.resolveBinder();
21 | });
22 |
23 | test(`Ensure objects are defined`, async () => {
24 | expect(targets.getTargets().length).toBe(1);
25 | expect(targets.getResolvedObjects(`FILE`).length).toBe(1);
26 | expect(targets.binderRequired()).toBe(false);
27 |
28 | const dspf = targets.searchForObject({ systemName: `ART301D`, type: `FILE` });
29 | expect(dspf).toBeDefined();
30 | });
31 | });
--------------------------------------------------------------------------------
/vs/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | // A launch configuration that compiles the extension and then opens it inside a new window
2 | {
3 | "version": "0.2.0",
4 | "configurations": [
5 | {
6 | "type": "extensionHost",
7 | "request": "launch",
8 | "name": "Launch Client",
9 | "runtimeExecutable": "${execPath}",
10 | "args": ["--extensionDevelopmentPath=${workspaceFolder:vs}"],
11 | "outFiles": ["${workspaceFolder:vs}/out/**/*.js"],
12 | "sourceMaps": true,
13 | "preLaunchTask": {
14 | "type": "npm",
15 | "script": "webpack:dev"
16 | },
17 | "sourceMapPathOverrides": {
18 | "webpack://vscode-sourceorbit-client/./*": "${workspaceFolder:vs}/client/*"
19 | },
20 | },
21 | {
22 | "type": "node",
23 | "request": "attach",
24 | "name": "Attach to Server",
25 | "port": 8720,
26 | "restart": true,
27 | "outFiles": ["${workspaceFolder:vs}/out/**/*.js"],
28 | "sourceMaps": true,
29 | "sourceMapPathOverrides": {
30 | "webpack://vscode-sourceorbit-server/./*": "${workspaceFolder:vs}/server/*"
31 | },
32 | },
33 |
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/cli/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Debug rmake",
9 | "type": "node",
10 | "request": "launch",
11 | "cwd": "${workspaceFolder:cli}",
12 | "program": "${workspaceFolder:cli}/dist/index.js",
13 | "sourceMaps": true,
14 | "args": ["-d", "/Users/barry/Downloads/stevefiles2", "--verbose"],
15 | "preLaunchTask": {
16 | "type": "npm",
17 | "script": "webpack:dev"
18 | },
19 | },
20 | {
21 | "name": "Debug MCP",
22 | "type": "node",
23 | "request": "launch",
24 | "cwd": "${workspaceFolder:cli}",
25 | "program": "${workspaceFolder:cli}/dist/index.js",
26 | "sourceMaps": true,
27 | "args": ["-d", "/Users/barry/Repos/ibmi-company_system", "--verbose", "-bf", "make", "-f", "qrpglesrc/employees.pgm.sqlrpgle"],
28 | "preLaunchTask": {
29 | "type": "npm",
30 | "script": "webpack:dev"
31 | },
32 | },
33 | ]
34 | }
--------------------------------------------------------------------------------
/cli/src/builders/make/folderSettings.ts:
--------------------------------------------------------------------------------
1 | import * as path from "path";
2 | import { readFileSync } from "fs";
3 | import { warningOut } from "../../cli";
4 | import { ReadFileSystem } from "../../readFileSystem";
5 | import { getFiles } from "../../utils";
6 |
7 | export interface FolderOptions {
8 | version?: "0.0.1",
9 | build?: {
10 | // objlib?: string, We don't support objlib
11 | tgtCcsid?: string
12 | }
13 | }
14 |
15 | /**
16 | * Fetch the folder specific settings for a project
17 | */
18 | export function getFolderOptions(cwd: string) {
19 | // Then fetch the directory specific settings
20 | const ibmiFiles = getFiles(cwd, `**/.ibmi.json`);
21 |
22 | let folderSettings: { [key: string]: FolderOptions } = {};
23 |
24 | for (const ibmiFile of ibmiFiles) {
25 | const relative = path.relative(cwd, ibmiFile);
26 | const folder = path.dirname(relative);
27 |
28 | try {
29 | folderSettings[folder] = JSON.parse(readFileSync(ibmiFile, { encoding: `utf-8` }));
30 | } catch (e) {
31 | warningOut(`make: Failed to read ${relative}.`);
32 | }
33 | }
34 |
35 | return folderSettings;
36 | }
--------------------------------------------------------------------------------
/cli/test/assume_pgms_copy.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import { setupFixture } from './fixtures/projects';
5 | import { ReadFileSystem } from '../src/readFileSystem';
6 |
7 | const cwd = setupFixture(`override_objref`);
8 |
9 | // This issue was occuring when you had two files with the same name, but different extensions.
10 |
11 | describe(`assume programs tests`, () => {
12 | const project = setupFixture(`assume_pgms_copy`);
13 |
14 | const fs = new ReadFileSystem();
15 | const targets = new Targets(project.cwd, fs);
16 | targets.setAssumePrograms(true);
17 |
18 | beforeAll(async () => {
19 | project.setup();
20 | await targets.loadProject();
21 |
22 | expect(targets.getTargets().length).toBeGreaterThan(0);
23 | targets.resolveBinder();
24 | });
25 |
26 | test(`Ensure copybooks are not objects`, async () => {
27 | const resolved = targets.getResolvedObjects();
28 | const targetObjects = targets.getTargets();
29 | expect(resolved.length).toBe(1);
30 | expect(targetObjects.length).toBe(1);
31 | })
32 | });
--------------------------------------------------------------------------------
/cli/test/fixtures/auto_rename1/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Dave Asta
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/pages/extension/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | ## VS Code Marketplace
4 |
5 | The Source Orbit extension can be installed from the VS Code Marketplace: [Source Orbit](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit).
6 |
7 |
8 | 
9 |
10 | ---
11 |
12 | ## Open VSX Registry
13 |
14 | The extension can also be downloaded and manually installed from the Open VSX Registry: [Source Orbit](https://open-vsx.org/extension/IBM/vscode-sourceorbit).
15 |
16 |
17 | 
18 |
19 | ---
20 |
21 | ## Suggested Extensions
22 |
23 | It is recommended to install the IBM i Project Explorer extension as it integrates with the Source Orbit extension. This can be done from the VS Code Marketplace: [IBM i Project Explorer](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-ibmi-projectexplorer).
24 |
25 | 
--------------------------------------------------------------------------------
/vs/server/webpack.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable @typescript-eslint/no-var-requires */
3 | /*---------------------------------------------------------------------------------------------
4 | * Copyright (c) Microsoft Corporation. All rights reserved.
5 | * Licensed under the MIT License. See License.txt in the project root for license information.
6 | *--------------------------------------------------------------------------------------------*/
7 |
8 | 'use strict';
9 |
10 | const withDefaults = require(`../shared.webpack.config.js`);
11 | const path = require(`path`);
12 | const webpack = require(`webpack`);
13 |
14 | module.exports = withDefaults({
15 | context: path.join(__dirname),
16 | entry: {
17 | extension: `./src/server.ts`,
18 | },
19 | output: {
20 | filename: `server.js`,
21 | path: path.join(__dirname, `..`, `out`)
22 | },
23 | plugins: [
24 | new webpack.DefinePlugin({
25 | 'process.env.LANGUAGE_TOOLS_ENABLED': process.env.LANGUAGE_TOOLS_ENABLED || `true`,
26 | 'process.env.LINTER_ENABLED': process.env.LINTER_ENABLED || `true`,
27 | 'process.env.FORMATTER_ENABLED': process.env.FORMATTER_ENABLED || `true`,
28 | }),
29 | ],
30 | });
--------------------------------------------------------------------------------
/cli/test/sqlReferenceWith.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import path from 'path';
5 | import { setupFixture } from './fixtures/projects';
6 | import { ReadFileSystem } from '../src/readFileSystem';
7 |
8 | async function setupScopeAnalysis(targets: Targets) {
9 | await targets.loadProject();
10 |
11 | expect(targets.getTargets().length).toBeGreaterThan(0);
12 | targets.resolveBinder();
13 | }
14 |
15 | describe(`sql_references_with tests`, () => {
16 | const project = setupFixture(`sql_ref_with`)
17 |
18 | const fs = new ReadFileSystem();
19 | const targets = new Targets(project.cwd, fs);
20 |
21 | beforeAll(async () => {
22 | project.setup();
23 | await setupScopeAnalysis(targets);
24 | });
25 |
26 | test(`SQL with clause`, async () => {
27 | const myPgm = targets.getTarget({ systemName: `SQLWITHPGM`, type: `PGM` });
28 | expect(myPgm.relativePath).toBe(path.join(`sqlwithpgm.pgm.sqlrpgle`));
29 |
30 | const moduleLogs = targets.logger.getLogsFor(myPgm.relativePath);
31 | expect(moduleLogs.length).toBe(1);
32 | expect(moduleLogs[0].message).toBe(`No object found for reference 'TABLE1'`);
33 | });
34 | });
--------------------------------------------------------------------------------
/.github/workflows/webpack.yaml:
--------------------------------------------------------------------------------
1 | name: NodeJS with Webpack
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | push:
7 | branches: ["main"]
8 | paths:
9 | - 'vs/**'
10 |
11 | pull_request:
12 | branches: ["main"]
13 | paths:
14 | - 'vs/**'
15 |
16 | jobs:
17 | build:
18 | name: Build and Package
19 |
20 | runs-on: ubuntu-latest
21 |
22 | strategy:
23 | matrix:
24 | node-version: [18.x]
25 |
26 | defaults:
27 | run:
28 | working-directory: ./vs
29 |
30 | steps:
31 | - name: Checkout
32 | uses: actions/checkout@v4
33 |
34 | - name: Use Node.js ${{ matrix.node-version }}
35 | uses: actions/setup-node@v4
36 | with:
37 | node-version: ${{ matrix.node-version }}
38 | registry-url: 'https://registry.npmjs.org'
39 |
40 | - name: Install NPM Dependencies
41 | run: |
42 | npm install
43 | npm install -g vsce
44 |
45 | - name: Build and Package
46 | run: |
47 | npm run webpack
48 | vsce package
49 |
50 | - name: Upload VSIX
51 | uses: actions/upload-artifact@v4
52 | with:
53 | name: VSIX
54 | path: ./vs/*.vsix
55 | if-no-files-found: error
56 |
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qddssrc/employee.table:
--------------------------------------------------------------------------------
1 | -- https://www.ibm.com/docs/en/i/7.3?topic=tables-employee-table-employee
2 |
3 | CREATE OR REPLACE TABLE EMPLOYEE
4 | (EMPNO CHAR(6) NOT NULL,
5 | FIRSTNME VARCHAR(12) NOT NULL,
6 | MIDINIT CHAR(1) NOT NULL,
7 | LASTNAME VARCHAR(15) NOT NULL,
8 | WORKDEPT CHAR(3) ,
9 | PHONENO CHAR(4) ,
10 | HIREDATE DATE ,
11 | JOB CHAR(8) ,
12 | EDLEVEL SMALLINT NOT NULL,
13 | SEX CHAR(1) ,
14 | BIRTHDATE DATE ,
15 | SALARY DECIMAL(9,2) ,
16 | BONUS DECIMAL(9,2) ,
17 | COMM DECIMAL(9,2) ,
18 | PRIMARY KEY (EMPNO));
19 |
20 | -- Remove circular reference
21 | -- ALTER TABLE EMPLOYEE
22 | -- ADD FOREIGN KEY RED (WORKDEPT)
23 | -- REFERENCES DEPARTMENT
24 | -- ON DELETE SET NULL;
25 |
26 | ALTER TABLE EMPLOYEE
27 | ADD CONSTRAINT NUMBER
28 | CHECK (PHONENO >= '0000' AND PHONENO <= '9998');
29 |
30 | -- CREATE UNIQUE INDEX XEMP1
31 | -- ON EMPLOYEE (EMPNO);
32 |
33 | -- CREATE INDEX XEMP2
34 | -- ON EMPLOYEE (WORKDEPT);
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qsqlsrc/employee.table:
--------------------------------------------------------------------------------
1 | -- https://www.ibm.com/docs/en/i/7.3?topic=tables-employee-table-employee
2 |
3 | CREATE OR REPLACE TABLE EMPLOYEE
4 | (EMPNO CHAR(6) NOT NULL,
5 | FIRSTNME VARCHAR(12) NOT NULL,
6 | MIDINIT CHAR(1) NOT NULL,
7 | LASTNAME VARCHAR(15) NOT NULL,
8 | WORKDEPT CHAR(3) ,
9 | PHONENO CHAR(4) ,
10 | HIREDATE DATE ,
11 | JOB CHAR(8) ,
12 | EDLEVEL SMALLINT NOT NULL,
13 | SEX CHAR(1) ,
14 | BIRTHDATE DATE ,
15 | SALARY DECIMAL(9,2) ,
16 | BONUS DECIMAL(9,2) ,
17 | COMM DECIMAL(9,2) ,
18 | PRIMARY KEY (EMPNO));
19 |
20 | -- Remove circular reference
21 | -- ALTER TABLE EMPLOYEE
22 | -- ADD FOREIGN KEY RED (WORKDEPT)
23 | -- REFERENCES DEPARTMENT
24 | -- ON DELETE SET NULL;
25 |
26 | ALTER TABLE EMPLOYEE
27 | ADD CONSTRAINT NUMBER
28 | CHECK (PHONENO >= '0000' AND PHONENO <= '9998');
29 |
30 | -- CREATE UNIQUE INDEX XEMP1
31 | -- ON EMPLOYEE (EMPNO);
32 |
33 | -- CREATE INDEX XEMP2
34 | -- ON EMPLOYEE (WORKDEPT);
--------------------------------------------------------------------------------
/vs/client/src/views/impactView/ileImpactedObjectTreeItem.ts:
--------------------------------------------------------------------------------
1 | import { ImpactedObject } from '@ibm/sourceorbit/dist/src/targets';
2 | import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri, WorkspaceFolder } from "vscode";
3 | import { TypeIcons } from '../utils';
4 | import path = require('path');
5 |
6 | export class ILEImpactedObjectTreeItem extends TreeItem {
7 | constructor(public workspaceFolder: WorkspaceFolder, private impactedObject: ImpactedObject) {
8 | super(`${impactedObject.ileObject.systemName}.${impactedObject.ileObject.type}`, impactedObject.children.length > 0 ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None);
9 | // const logs = TargetsManager.getLogs(workspaceFolder, ileObject);
10 |
11 | this.description = impactedObject.ileObject.relativePath || `No source`;
12 | this.iconPath = new ThemeIcon(TypeIcons[impactedObject.ileObject.type] || `unverified`);
13 |
14 | this.contextValue = `ileObject`;
15 |
16 | if (impactedObject.ileObject.relativePath) {
17 | this.resourceUri = Uri.from({ scheme: `file`, path: path.join(this.workspaceFolder.uri.fsPath, impactedObject.ileObject.relativePath) });
18 | }
19 | }
20 |
21 | async getChildren(): Promise<(ILEImpactedObjectTreeItem)[]> {
22 | return this.impactedObject.children.map(c => new ILEImpactedObjectTreeItem(this.workspaceFolder, c));
23 | }
24 | }
--------------------------------------------------------------------------------
/cli/test/sqlReference.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import path from 'path';
5 | import { setupFixture } from './fixtures/projects';
6 | import { ReadFileSystem } from '../src/readFileSystem';
7 |
8 |
9 | async function setupScopeAnalysis(targets: Targets) {
10 | await targets.loadProject();
11 |
12 | expect(targets.getTargets().length).toBeGreaterThan(0);
13 | targets.resolveBinder();
14 | }
15 |
16 | describe(`sql_references tests (internal scope analysis)`, () => {
17 | const project = setupFixture(`sql_references`);
18 |
19 | const fs = new ReadFileSystem();
20 | const targets = new Targets(project.cwd, fs);
21 |
22 | beforeAll(async () => {
23 | project.setup();
24 | await setupScopeAnalysis(targets);
25 | });
26 |
27 | test(`Check stock (with internal scope analysis)`, async () => {
28 | const myPgm = targets.getTarget({ systemName: `SQLREFPGM`, type: `PGM` });
29 | expect(myPgm.relativePath).toBe(path.join(`qrpglesrc`, `sqlrefpgm.pgm.sqlrpgle`));
30 | expect(myPgm.deps.length).toBe(1);
31 |
32 | const empTable = myPgm.deps[0];
33 | expect(empTable.systemName).toBe(`STOCK`);
34 | expect(empTable.type).toBe(`FILE`);
35 | expect(empTable.relativePath).toBe(path.join(`qddssrc`, `stock.table`));
36 | });
37 | });
--------------------------------------------------------------------------------
/cli/test/fixtures/from_qsys/qsqlsrc/rsnmst.table:
--------------------------------------------------------------------------------
1 | CREATE OR REPLACE TABLE RSNMST (
2 | -- SQL150B 10 REUSEDLT(*NO) in table RSNMST in PAYROLL1 ignored.
3 | ACREC CHAR(1) CCSID 37 NOT NULL DEFAULT '' ,
4 | RSCDE CHAR(8) CCSID 37 NOT NULL DEFAULT '' ,
5 | RSDSC CHAR(50) CCSID 37 NOT NULL DEFAULT '' ,
6 | RSHRC DECIMAL(7, 1) NOT NULL DEFAULT 0 ,
7 | RSHRY DECIMAL(9, 1) NOT NULL DEFAULT 0 ,
8 | RSHRP DECIMAL(9, 1) NOT NULL DEFAULT 0 ,
9 | PRIMARY KEY( RSCDE ) )
10 |
11 | RCDFMT RCRSN ;
12 |
13 | LABEL ON COLUMN RSNMST
14 | ( RSCDE IS 'REASON CODE' ,
15 | RSDSC IS 'REASON CODE DESCRIPTION' ,
16 | RSHRC IS 'RSN CDE HRS CUR MTH' ,
17 | RSHRY IS 'RSN CDE HRS YTD' ,
18 | RSHRP IS 'RSN CDE HRS PRIOR YR' ) ;
19 |
20 | LABEL ON COLUMN RSNMST
21 | ( ACREC TEXT IS 'ACTIVE RECORD CODE' ,
22 | RSCDE TEXT IS 'REASON CODE' ,
23 | RSDSC TEXT IS 'REASON CODE DESCRIPTION' ,
24 | RSHRC TEXT IS 'REASON CODE HRS CURR MONTH' ,
25 | RSHRY TEXT IS 'REASON CODE HRS YEAR TO DATE' ,
26 | RSHRP TEXT IS 'REASON CODE HOURS PRIOR YEAR' ) ;
27 |
28 | GRANT DELETE , INSERT , SELECT , UPDATE
29 | ON RSNMST TO PUBLIC ;
30 |
31 | -- GRANT ALTER , DELETE , INDEX , INSERT , REFERENCES , SELECT , UPDATE
32 | -- ON RSNMST TO WDSCTEST WITH GRANT OPTION ;
33 |
34 |
--------------------------------------------------------------------------------
/cli/test/fixtures/sql_long_names/rpgle/db.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt nomain;
4 |
5 | dcl-proc getLiveBalance;
6 | dcl-pi *n likeDs(liveResultT);
7 | type char(1) const;
8 | cusno int(10) const;
9 | end-pi;
10 |
11 | dcl-ds liveResult likeds(liveResultT);
12 |
13 | dcl-f trans qualified usropn usage(*input);
14 | dcl-ds transaction likerec(trans.transfmt);
15 |
16 | liveResult.total = 0;
17 | liveResult.count = 0;
18 |
19 | select;
20 | when (type = RLA);
21 | // This RLA check is a bit of a hack.
22 | // In the future, we might want to use
23 | // a keyed field or an LF to look for
24 | // the card by customer id instead of
25 | // manually scanning the file.
26 |
27 | // The larger the file, the longer this will take
28 |
29 | OPEN trans;
30 |
31 | read trans.transfmt transaction;
32 | dow not %eof;
33 | if (transaction.TCUS = cusno);
34 | liveResult.total += transaction.TAMT;
35 | liveResult.count += 1;
36 | endif;
37 | read trans.transfmt transaction;
38 | enddo;
39 |
40 | CLOSE trans;
41 |
42 | when (type = SQL);
43 | EXEC SQL
44 | SELECT count(*), coalesce(sum(TAMT), 0)
45 | INTO :liveResult.count, :liveResult.total
46 | FROM TRANSACTION
47 | WHERE TCUS = :cusno;
48 | endsl;
49 |
50 | return liveResult;
51 |
52 | end-proc;
--------------------------------------------------------------------------------
/cli/test/fixtures/multi_module_two/rpgle/db.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt nomain;
4 |
5 | dcl-pr getFirst char(15) extproc('GETFIRST');
6 | end-pr;
7 |
8 | dcl-pr getSurname char(15) extproc('GETSURNAME');
9 | end-pr;
10 |
11 | dcl-pr random int(10) extproc('RANDOM');
12 | low packed(7) const;
13 | high packed(7) const;
14 | end-pr;
15 |
16 | dcl-pr getStreetType char(3) extproc('GETSTREETTYPE');
17 | end-pr;
18 |
19 | dcl-pr getCity char(15) extproc('GETCITY');
20 | end-pr;
21 |
22 | dcl-pr getState char(2) extproc('GETSTATE');
23 | end-pr;
24 |
25 | dcl-proc createCustomer export;
26 | dcl-pi *n int(10);
27 | type char(1) const;
28 | end-pi;
29 |
30 | dcl-f customer qualified keyed usropn usage(*output);
31 | dcl-ds cust likerec(customer.custfmt);
32 |
33 | cust.FIRSTNME = getFirst();
34 | cust.LASTNAME = getSurname();
35 | cust.PHONENO = %char(random(1111:9999));
36 | cust.CREATED = %date;
37 | cust.ADDR1 = %char(random(1:9999)) + ' ' + %trimr(getSurname()) + ' ' + getStreetType();
38 | cust.CITY = getCity();
39 | cust.STATE = getState();
40 | cust.ZIP = %char(random(10000:99999));
41 |
42 | select;
43 | when (type = '1'); //RLA
44 | OPEN customer;
45 | write customer.CUSTFMT cust;
46 | CLOSE customer;
47 | when (type = '2'); //SQL
48 | EXEC SQL
49 | INSERT INTO CUSTOMER
50 | VALUES(:cust);
51 |
52 | other;
53 | return -1;
54 | endsl;
55 |
56 | end-proc;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qddssrc/employee.table:
--------------------------------------------------------------------------------
1 | -- https://www.ibm.com/docs/en/i/7.3?topic=tables-employee-table-employee
2 |
3 | --%METADATA *
4 | -- %TEXT Employee File *
5 | --%EMETADATA *
6 |
7 | CREATE OR REPLACE TABLE EMPLOYEE
8 | (EMPNO CHAR(6) NOT NULL,
9 | FIRSTNME VARCHAR(12) NOT NULL,
10 | MIDINIT CHAR(1) NOT NULL,
11 | LASTNAME VARCHAR(15) NOT NULL,
12 | WORKDEPT CHAR(3) ,
13 | PHONENO CHAR(4) ,
14 | HIREDATE DATE ,
15 | JOB CHAR(8) ,
16 | EDLEVEL SMALLINT NOT NULL,
17 | SEX CHAR(1) ,
18 | BIRTHDATE DATE ,
19 | SALARY DECIMAL(9,2) ,
20 | BONUS DECIMAL(9,2) ,
21 | COMM DECIMAL(9,2) ,
22 | PRIMARY KEY (EMPNO));
23 |
24 | ALTER TABLE EMPLOYEE
25 | ADD FOREIGN KEY RED (WORKDEPT)
26 | REFERENCES DEPARTMENT
27 | ON DELETE SET NULL;
28 |
29 | ALTER TABLE EMPLOYEE
30 | ADD CONSTRAINT NUMBER
31 | CHECK (PHONENO >= '0000' AND PHONENO <= '9999');
32 |
33 | -- CREATE UNIQUE INDEX XEMP1
34 | -- ON EMPLOYEE (EMPNO);
35 |
36 | -- CREATE INDEX XEMP2
37 | -- ON EMPLOYEE (WORKDEPT);
--------------------------------------------------------------------------------
/cli/test/fixtures/multi_module/qrpglesrc/utils.sqlrpgle:
--------------------------------------------------------------------------------
1 | **FREE
2 |
3 | Ctl-Opt NoMain;
4 |
5 | /copy 'qrpgleref/system.rpgleinc'
6 | /copy 'qrpgleref/utils.rpgleinc'
7 |
8 | Dcl-S JobTypeGlobal Char(1);
9 |
10 | Dcl-Proc Utils_Lower Export;
11 | Dcl-Pi *N Char(10);
12 | pValue Char(10) Value;
13 | End-Pi;
14 |
15 | EXEC SQL SET :pValue = LOWER(:pValue);
16 |
17 | Return pValue;
18 | End-Proc;
19 |
20 | Dcl-Proc Utils_Print Export;
21 | Dcl-Pi *N;
22 | Text Varchar(512) Const;
23 | End-Pi;
24 |
25 | Dcl-s Type Char(1);
26 |
27 | Type = Utils_JobType();
28 |
29 | If (Type = 'I');
30 | printf_jl(%trim(Text) + x'25');
31 | Else;
32 | printf(%trim(Text) + x'25');
33 | Endif;
34 | End-Proc;
35 |
36 | Dcl-Proc Utils_Qsh Export;
37 | Dcl-Pi *N Ind;
38 | Command Varchar(512) Const;
39 | End-Pi;
40 |
41 | return system('QSH CMD(''' + %Trim(Command) + ''')') = 0;
42 | End-Proc;
43 |
44 | dcl-proc Utils_JobType export;
45 | dcl-pi *n char(1) end-pi;
46 | dcl-pr QUSRJOBI extpgm;
47 | *n char(32766) options(*varsize);
48 | *n int(10:0) const;
49 | *n char(8) const;
50 | *n char(26) const;
51 | *n char(16) const;
52 | end-pr;
53 |
54 | dcl-ds Returned len(86);
55 | JobType char(1) pos(61);
56 | end-ds;
57 |
58 | If (JobTypeGlobal = *BLANK);
59 | QUSRJOBI(Returned:%size(Returned):'JOBI0100':'*':'');
60 |
61 | JobTypeGlobal = JobType;
62 | Endif;
63 |
64 | Return JobTypeGlobal;
65 | end-proc;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qddssrc/employee.table:
--------------------------------------------------------------------------------
1 | -- https://www.ibm.com/docs/en/i/7.3?topic=tables-employee-table-employee
2 |
3 | --%METADATA *
4 | -- %TEXT Employee File *
5 | --%EMETADATA *
6 |
7 | CREATE OR REPLACE TABLE EMPLOYEE
8 | (EMPNO CHAR(6) NOT NULL,
9 | FIRSTNME VARCHAR(12) NOT NULL,
10 | MIDINIT CHAR(1) NOT NULL,
11 | LASTNAME VARCHAR(15) NOT NULL,
12 | WORKDEPT CHAR(3) ,
13 | PHONENO CHAR(4) ,
14 | HIREDATE DATE ,
15 | JOB CHAR(8) ,
16 | EDLEVEL SMALLINT NOT NULL,
17 | SEX CHAR(1) ,
18 | BIRTHDATE DATE ,
19 | SALARY DECIMAL(9,2) ,
20 | BONUS DECIMAL(9,2) ,
21 | COMM DECIMAL(9,2) ,
22 | PRIMARY KEY (EMPNO));
23 |
24 | ALTER TABLE EMPLOYEE
25 | ADD FOREIGN KEY RED (WORKDEPT)
26 | REFERENCES DEPARTMENT
27 | ON DELETE SET NULL;
28 |
29 | ALTER TABLE EMPLOYEE
30 | ADD CONSTRAINT NUMBER
31 | CHECK (PHONENO >= '0000' AND PHONENO <= '9999');
32 |
33 | -- CREATE UNIQUE INDEX XEMP1
34 | -- ON EMPLOYEE (EMPNO);
35 |
36 | -- CREATE INDEX XEMP2
37 | -- ON EMPLOYEE (WORKDEPT);
--------------------------------------------------------------------------------
/vs/client/src/gitEventHandler.ts:
--------------------------------------------------------------------------------
1 |
2 | import { ExtensionContext, WorkspaceFolder } from 'vscode';
3 | import { getDeployGitFiles as getChangedFiles, getGitAPI, lastBranch } from './git';
4 | import { LanguageClientManager } from './languageClientManager';
5 | import { ImpactView } from './views/impactView';
6 |
7 | export namespace GitEventHandler {
8 | export function setup(context: ExtensionContext, gitImpactView: ImpactView, workspaceFolders: WorkspaceFolder[]) {
9 | const gitApi = getGitAPI();
10 |
11 | if (gitApi) {
12 | for (const workspaceFolder of workspaceFolders) {
13 | const repo = gitApi.getRepository(workspaceFolder.uri);
14 | if (repo) {
15 | const workspaceUri = workspaceFolder.uri.toString();
16 | const head = repo.state.HEAD;
17 | if (head && head.name) {
18 | lastBranch[workspaceUri] = head.name;
19 |
20 | context.subscriptions.push(repo.state.onDidChange((_e) => {
21 | const currentBranch = head.name;
22 | if (currentBranch) {
23 | if (lastBranch[workspaceUri] && currentBranch !== lastBranch[workspaceUri]) {
24 | gitImpactView.showImpactFor([]);
25 | LanguageClientManager.reloadProject(workspaceFolder);
26 |
27 | } else {
28 | getChangedFiles(workspaceFolder).then(files => {
29 | gitImpactView.showImpactFor(files);
30 | });
31 |
32 | }
33 |
34 | lastBranch[workspaceUri] = currentBranch;
35 | }
36 | }));
37 | }
38 | }
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/vs/client/src/ProjectExplorer.ts:
--------------------------------------------------------------------------------
1 | import { Extension, extensions } from "vscode";
2 | import { IBMiProjectExplorer } from "@ibm/vscode-ibmi-projectexplorer-types/ibmiProjectExplorer";
3 | import { ProjectManager } from "@ibm/vscode-ibmi-projectexplorer-types/projectManager";
4 | import ProjectExplorer from "@ibm/vscode-ibmi-projectexplorer-types/views/projectExplorer";
5 |
6 | let baseExtension: Extension | undefined;
7 |
8 | export async function loadIBMiProjectExplorer(): Promise {
9 | if (!baseExtension) {
10 | baseExtension = (extensions ? extensions.getExtension(`IBM.vscode-ibmi-projectexplorer`) : undefined);
11 | }
12 |
13 | if (baseExtension) {
14 | if (!baseExtension.isActive) {
15 | await baseExtension.activate();
16 | }
17 | }
18 |
19 | return (baseExtension && baseExtension.isActive && baseExtension.exports ? baseExtension.exports : undefined);
20 | }
21 |
22 | /**
23 | * Get the access to the Project Manager APIs.
24 | */
25 | export function getProjectManager(): typeof ProjectManager | undefined {
26 | return (baseExtension && baseExtension.isActive && baseExtension.exports ? baseExtension.exports.projectManager : undefined);
27 | }
28 |
29 | /**
30 | * Get the access to the Project Explorer APIs.
31 | */
32 | export function getProjectExplorer(): ProjectExplorer | undefined {
33 | return (baseExtension && baseExtension.isActive && baseExtension.exports ? baseExtension.exports.projectExplorer : undefined);
34 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/dds_deps/PROVIDER.PF:
--------------------------------------------------------------------------------
1 | *%METADATA *
2 | * %TEXT Provider file *
3 | *%EMETADATA *
4 | REF(SAMREF)
5 | R FPROV
6 | PRID R
7 | PROVNM R
8 | PRCONT 30 TEXT('CONTACT PERSON')
9 | PRPHONE R REFFLD(PHONE)
10 | PRVAT R REFFLD(VATNUM)
11 | PRMAIL R REFFLD(EMAIL)
12 | PRLINE1 R REFFLD(ADRLINE)
13 | PRLINE2 R REFFLD(ADRLINE)
14 | PRLINE3 R REFFLD(ADRLINE)
15 | PRZIP R REFFLD(ZIPCOD)
16 | PRCITY R REFFLD(CITY)
17 | PRCOUN R REFFLD(COID)
18 | PRCREA L TEXT('CREATION DATE')
19 | COLHDG('CREAETION' 'DATE')
20 | PRMOD Z TEXT('LAST MODIFICATION')
21 | COLHDG('LAST' 'MODIFICATION')
22 | PRMODID 10 TEXT('LAS MOD BY')
23 | COLHDG('LAST' 'MODIF.' 'BY')
24 | PRDEL R REFFLD(DLCODE)
25 |
--------------------------------------------------------------------------------
/cli/test/fixtures/override_objref/PROVIDER.PF:
--------------------------------------------------------------------------------
1 | *%METADATA *
2 | * %TEXT Provider file *
3 | *%EMETADATA *
4 | REF(SAMREF)
5 | R FPROV
6 | PRID R
7 | PROVNM R
8 | PRCONT 30 TEXT('CONTACT PERSON')
9 | PRPHONE R REFFLD(PHONE)
10 | PRVAT R REFFLD(VATNUM)
11 | PRMAIL R REFFLD(EMAIL)
12 | PRLINE1 R REFFLD(ADRLINE)
13 | PRLINE2 R REFFLD(ADRLINE)
14 | PRLINE3 R REFFLD(ADRLINE)
15 | PRZIP R REFFLD(ZIPCOD)
16 | PRCITY R REFFLD(CITY)
17 | PRCOUN R REFFLD(COID)
18 | PRCREA L TEXT('CREATION DATE')
19 | COLHDG('CREAETION' 'DATE')
20 | PRMOD Z TEXT('LAST MODIFICATION')
21 | COLHDG('LAST' 'MODIFICATION')
22 | PRMODID 10 TEXT('LAS MOD BY')
23 | COLHDG('LAST' 'MODIF.' 'BY')
24 | PRDEL R REFFLD(DLCODE)
25 |
--------------------------------------------------------------------------------
/cli/test/fixtures/dds_deps_with_refs/PROVIDER.PF:
--------------------------------------------------------------------------------
1 | *%METADATA *
2 | * %TEXT Provider file *
3 | *%EMETADATA *
4 | REF(SAMREF)
5 | R FPROV
6 | PRID R
7 | PROVNM R
8 | PRCONT 30 TEXT('CONTACT PERSON')
9 | PRPHONE R REFFLD(PHONE)
10 | PRVAT R REFFLD(VATNUM)
11 | PRMAIL R REFFLD(EMAIL)
12 | PRLINE1 R REFFLD(ADRLINE)
13 | PRLINE2 R REFFLD(ADRLINE)
14 | PRLINE3 R REFFLD(ADRLINE)
15 | PRZIP R REFFLD(ZIPCOD)
16 | PRCITY R REFFLD(CITY)
17 | PRCOUN R REFFLD(COID)
18 | PRCREA L TEXT('CREATION DATE')
19 | COLHDG('CREAETION' 'DATE')
20 | PRMOD Z TEXT('LAST MODIFICATION')
21 | COLHDG('LAST' 'MODIFICATION')
22 | PRMODID 10 TEXT('LAS MOD BY')
23 | COLHDG('LAST' 'MODIF.' 'BY')
24 | PRDEL R REFFLD(DLCODE)
25 |
--------------------------------------------------------------------------------
/vs/client/src/views/projectExplorer/sourceOrbitTreeItem.ts:
--------------------------------------------------------------------------------
1 | import { ProjectExplorerTreeItem } from "@ibm/vscode-ibmi-projectexplorer-types/views/projectExplorer/projectExplorerTreeItem";
2 | import { Event, EventEmitter, ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode";
3 | import { LanguageClientManager } from '../../languageClientManager';
4 | import { ILEObjectTreeItem } from './ileObjectTreeItem';
5 |
6 | export class SourceOrbitTreeItem extends TreeItem implements ProjectExplorerTreeItem {
7 | private _onDidChangeTreeData: EventEmitter = new EventEmitter();
8 | readonly onDidChangeTreeData: Event = this._onDidChangeTreeData.event;
9 |
10 | constructor(public workspaceFolder: WorkspaceFolder) {
11 | super(`Source Orbit`, TreeItemCollapsibleState.Collapsed);
12 | this.iconPath = new ThemeIcon(`globe`);
13 | this.contextValue = `objectsView`;
14 | }
15 |
16 | refresh() {
17 | this._onDidChangeTreeData.fire();
18 | }
19 |
20 | async getChildren(): Promise {
21 | const isProjectReady = await LanguageClientManager.isReady(this.workspaceFolder);
22 | if (!isProjectReady) {
23 | await LanguageClientManager.reloadProject(this.workspaceFolder);
24 | }
25 |
26 | const objects = await LanguageClientManager.getResolvedObjects(this.workspaceFolder);
27 | return objects.map(o => new ILEObjectTreeItem(this.workspaceFolder, o, true));
28 | }
29 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qrpglesrc/empdet.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt nomain;
4 |
5 | /copy 'qrpgleref/empdet.rpgleinc'
6 |
7 | dcl-proc getEmployeeDetail export;
8 | dcl-pi *n like(employee_detail_t);
9 | empno char(6) const;
10 | end-pi;
11 |
12 | dcl-ds employee_detail likeds(employee_detail_t);
13 |
14 | exec sql
15 | select
16 | rtrim(firstnme) || ' ' || rtrim(lastname),
17 | salary + bonus + comm
18 | into
19 | :employee_detail.name,
20 | :employee_detail.netincome
21 | from
22 | employee
23 | where
24 | empno = :empno;
25 |
26 | if (sqlcode = 0);
27 | employee_detail.found = *on;
28 | else;
29 | employee_detail.found = *off;
30 | endif;
31 |
32 | return employee_detail;
33 | end-proc;
34 |
35 | dcl-proc getDeptDetail export;
36 | dcl-pi *n like(department_detail_t);
37 | deptno char(3) const;
38 | end-pi;
39 |
40 | dcl-ds department_detail likeds(department_detail_t);
41 |
42 | exec sql
43 | select
44 | rtrim(deptname),
45 | coalesce(location, 'N/A'),
46 | (select sum(salary + bonus + comm)
47 | from employee
48 | where workdept = :deptno)
49 | into
50 | :department_detail.deptname,
51 | :department_detail.location,
52 | :department_detail.totalsalaries
53 | from
54 | department
55 | where
56 | deptno = :deptno;
57 |
58 | if (sqlcode = 0);
59 | department_detail.found = *on;
60 | else;
61 | department_detail.found = *off;
62 | endif;
63 |
64 | return department_detail;
65 | end-proc;
--------------------------------------------------------------------------------
/cli/test/fixtures/dclcase/qrpglesrc/apival01s.rpgleinc:
--------------------------------------------------------------------------------
1 | **free
2 | // Constants
3 | // ---------
4 | // field & array sizes
5 | dcl-c APIVAL01S_MAX_DIM 1000; // max array size
6 | dcl-c APIVAL01S_DATA_LEN 100; // max field data length
7 | dcl-c APIVAL01S_FIELD_LEN 50; // max field name length
8 | dcl-c APIVAL01S_VALID_LEN 500; // max validation length
9 | dcl-c APIVAL01S_JSON_LEN 1000; // JSON error response size
10 | // type constants
11 | dcl-c APIVAL01S_TYPE_STRING 'string';
12 | dcl-c APIVAL01S_TYPE_NUMERIC 'numeric';
13 | dcl-c APIVAL01S_TYPE_DATE 'date';
14 |
15 | // DS templates
16 | // ------------
17 | // list of validations to perform
18 | dcl-ds APIVAL01S_validationsDs qualified template;
19 | field varchar(APIVAL01S_FIELD_LEN);
20 | type varchar(50);
21 | validations varchar(APIVAL01S_VALID_LEN) dim(6);
22 | end-ds;
23 |
24 | // perform validation for the given list of validations (validationDs)
25 | // with the given input data (note: required char!)
26 | // returns the number of errors found (if any)
27 | // if errors returned = 0 then the validation succeeded
28 | // in case of validation failure o_errorJson will contain a list of errors in JSON format
29 | dcl-pr APIVAL01S_iws_validate int(10) extproc(*dclcase);
30 | i_validationsDs likeds(APIVAL01S_validationsDs) dim(APIVAL01S_MAX_DIM);
31 | i_data varchar(APIVAL01S_DATA_LEN) dim(APIVAL01S_MAX_DIM);
32 | o_errorJson varchar(APIVAL01S_JSON_LEN);
33 | end-pr;
34 |
35 |
--------------------------------------------------------------------------------
/cli/test/cldclf.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import { setupFixture } from './fixtures/projects';
5 | import { ReadFileSystem } from '../src/readFileSystem';
6 |
7 | describe(`CL with DCLF`, () => {
8 | const project = setupFixture(`cldclf`);
9 |
10 | const fs = new ReadFileSystem();
11 | const targets = new Targets(project.cwd, fs);
12 |
13 | beforeAll(async () => {
14 | project.setup();
15 | await targets.loadProject();
16 |
17 | expect(targets.getTargets().length).toBeGreaterThan(0);
18 | targets.resolveBinder();
19 | });
20 |
21 | test(`Objects are loaded`, () => {
22 | expect(targets).toBeDefined();
23 | expect(targets.binderRequired()).toBeFalsy();
24 |
25 | const targetObjects = targets.getTargets();
26 |
27 | expect(targetObjects.length).toBe(2);
28 |
29 | expect(targetObjects.some(t => t.systemName === `APGM` && t.type === `PGM` && t.extension === `clle`)).toBeTruthy();
30 | expect(targetObjects.some(t => t.systemName === `DEPARTMENT` && t.type === `FILE` && t.extension === `table`)).toBeTruthy();
31 | });
32 |
33 | test(`CL has valid dependency`, () => {
34 | const apgm = targets.getTarget({systemName: `APGM`, type: `PGM`});
35 | expect(apgm).toBeDefined();
36 |
37 | const logs = targets.logger.getLogsFor(apgm.relativePath);
38 | expect(logs.length).toBe(0);
39 |
40 | expect(apgm.deps.length).toBe(1);
41 | expect(apgm.deps[0].systemName).toBe(`DEPARTMENT`);
42 | expect(apgm.deps[0].type).toBe(`FILE`);
43 | });
44 | });
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qrpglesrc/empdet.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt nomain;
4 |
5 | /copy 'qrpgleref/empdet.rpgleinc'
6 |
7 | dcl-proc getEmployeeDetail export;
8 | dcl-pi *n like(employee_detail_t);
9 | empno char(6) const;
10 | end-pi;
11 |
12 | dcl-ds employee_detail likeds(employee_detail_t);
13 |
14 | exec sql
15 | select
16 | rtrim(firstnme) || ' ' || rtrim(midinit) || ' ' || rtrim(lastname),
17 | salary + bonus + comm
18 | into
19 | :employee_detail.name,
20 | :employee_detail.netincome
21 | from
22 | employee
23 | where
24 | empno = :empno;
25 |
26 | if (sqlcode = 0);
27 | employee_detail.found = *on;
28 | else;
29 | employee_detail.found = *off;
30 | endif;
31 |
32 | return employee_detail;
33 | end-proc;
34 |
35 | dcl-proc getDeptDetail export;
36 | dcl-pi *n like(department_detail_t);
37 | deptno char(3) const;
38 | end-pi;
39 |
40 | dcl-ds department_detail likeds(department_detail_t);
41 |
42 | exec sql
43 | select
44 | rtrim(deptname),
45 | coalesce(location, 'N/A'),
46 | (select sum(salary + bonus + comm)
47 | from employee
48 | where workdept = :deptno)
49 | into
50 | :department_detail.deptname,
51 | :department_detail.location,
52 | :department_detail.totalsalaries
53 | from
54 | department
55 | where
56 | deptno = :deptno;
57 |
58 | if (sqlcode = 0);
59 | department_detail.found = *on;
60 | else;
61 | department_detail.found = *off;
62 | endif;
63 |
64 | return department_detail;
65 | end-proc;
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qddssrc/popdept.sql:
--------------------------------------------------------------------------------
1 | -------------------------------------------------------------------------------
2 | -- This procedure will create 5 records into the department table
3 | -------------------------------------------------------------------------------
4 |
5 | create or replace procedure popdept()
6 | language sql
7 | Result Sets 0
8 | Modifies SQL Data
9 | Specific popdept
10 | begin
11 | declare i int default 1;
12 | declare deptno char(3);
13 | declare deptname varchar(36);
14 | declare mgrno char(6);
15 | declare admrdept char(3);
16 | declare loc char(16);
17 |
18 | while i <= 5 do
19 | -- Generate random data (you can adjust this as needed)
20 | set deptno = right('000' || cast(rand()*1000 as int), 3);
21 | set mgrno = right('00000' || cast(rand()*1000000 as int), 6);
22 | set admrdept = right('000' || cast(rand()*1000 as int), 3);
23 | set loc = 'Location ' || deptno;
24 |
25 | -- Assign department names based on specified categories
26 | case
27 | when i = 1 then set deptname = 'Admin';
28 | when i = 2 then set deptname = 'IT';
29 | when i = 3 then set deptname = 'Finance';
30 | when i = 4 then set deptname = 'Management';
31 | when i = 5 then set deptname = 'HR';
32 | end case;
33 |
34 | -- Insert into department table
35 | insert into department (deptno, deptname, mgrno, admrdept, location)
36 | values (deptno, deptname, mgrno, admrdept, loc) with nc;
37 |
38 | set i = i + 1;
39 | end while;
40 | end;
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qsqlsrc/popdept.sqlprc:
--------------------------------------------------------------------------------
1 | -------------------------------------------------------------------------------
2 | -- This procedure will create 5 records into the department table
3 | -------------------------------------------------------------------------------
4 |
5 | create or replace procedure popdept()
6 | language sql
7 | Result Sets 0
8 | Modifies SQL Data
9 | Specific popdept
10 | begin
11 | declare i int default 1;
12 | declare deptno char(3);
13 | declare deptname varchar(36);
14 | declare mgrno char(6);
15 | declare admrdept char(3);
16 | declare loc char(16);
17 |
18 | while i <= 5 do
19 | -- Generate random data (you can adjust this as needed)
20 | set deptno = right('000' || cast(rand()*1000 as int), 3);
21 | set mgrno = right('00000' || cast(rand()*1000000 as int), 6);
22 | set admrdept = right('000' || cast(rand()*1000 as int), 3);
23 | set loc = 'Location ' || deptno;
24 |
25 | -- Assign department names based on specified categories
26 | case
27 | when i = 1 then set deptname = 'Admin';
28 | when i = 2 then set deptname = 'IT';
29 | when i = 3 then set deptname = 'Finance';
30 | when i = 4 then set deptname = 'Management';
31 | when i = 5 then set deptname = 'HR';
32 | end case;
33 |
34 | -- Insert into department table
35 | insert into department (deptno, deptname, mgrno, admrdept, location)
36 | values (deptno, deptname, mgrno, admrdept, loc) with nc;
37 |
38 | set i = i + 1;
39 | end while;
40 | end;
--------------------------------------------------------------------------------
/cli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@ibm/sourceorbit",
3 | "version": "1.4.1",
4 | "description": "IBM i dependency management tool",
5 | "bin": {
6 | "so": "./dist/index.js"
7 | },
8 | "publisher": "IBM",
9 | "main": "./dist/index.js",
10 | "types": "./dist/src/index.d.ts",
11 | "scripts": {
12 | "test": "vitest",
13 | "webpack:dev": "webpack --mode none --config ./webpack.config.js",
14 | "webpack": "webpack --mode production --config ./webpack.config.js",
15 | "local": "npm run webpack:dev && npm i -g",
16 | "deploy": "npm run webpack && npm i && npm publish --access public"
17 | },
18 | "keywords": [
19 | "ibmi",
20 | "iseries",
21 | "as400"
22 | ],
23 | "categories": [
24 | "Other"
25 | ],
26 | "author": "IBM",
27 | "license": "Apache 2",
28 | "repository": {
29 | "url": "https://github.com/IBM/sourceorbit"
30 | },
31 | "bugs": {
32 | "url": "https://github.com/IBM/sourceorbit/issues"
33 | },
34 | "homepage": "https://ibm.github.io/sourceorbit/#/",
35 | "devDependencies": {
36 | "glob": "^7.2.0",
37 | "merge-options": "^3.0.4",
38 | "ts-loader": "^9.4.4",
39 | "typescript": "^5.8.2",
40 | "vitest": "^3.0.8",
41 | "vscode-clle": "github:IBM/vscode-clle",
42 | "vscode-db2i": "github:halcyon-tech/vscode-db2i",
43 | "vscode-displayfile": "github:halcyon-tech/vscode-displayfile",
44 | "vscode-rpgle": "github:halcyon-tech/vscode-rpgle",
45 | "webpack": "^5.24.3",
46 | "webpack-cli": "^4.5.0"
47 | },
48 | "dependencies": {
49 | "@modelcontextprotocol/sdk": "^1.12.1",
50 | "crc-32": "https://cdn.sheetjs.com/crc-32-latest/crc-32-latest.tgz",
51 | "express": "^5.1.0"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/cli/src/logger.ts:
--------------------------------------------------------------------------------
1 | import { infoOut, warningOut } from "./cli";
2 |
3 | type LogType = "info"|"warning"|"includeFix"|"rename";
4 |
5 | type FileLogs = {[path: string]: FileLog[]};
6 |
7 | interface ChangeSuggestion {
8 | rename?: {
9 | path: string;
10 | newName: string;
11 | },
12 | lineContent?: string;
13 | }
14 |
15 | export interface FileLog {
16 | type: LogType;
17 | message: string;
18 | line?: number;
19 | range?: {
20 | start: number,
21 | end: number
22 | }
23 | change?: ChangeSuggestion;
24 | }
25 |
26 | export class Logger {
27 | private logs: FileLogs = {};
28 |
29 | constructor() {}
30 |
31 | flush(specificPath?: string) {
32 | if (specificPath) {
33 | this.logs[specificPath] = [];
34 | } else {
35 | this.logs = {}
36 | }
37 | }
38 |
39 | fileLog(path: string, log: FileLog) {
40 | switch (log.type) {
41 | case `info`: infoOut(`${path}${log.line ? `:${log.line}` : ``} - ${log.message}`); break;
42 | case `warning`: warningOut(`${path}${log.line ? `:${log.line}` : ``} - ${log.message}`); break;
43 | }
44 |
45 | if (!this.logs[path]) {
46 | this.logs[path] = [];
47 | }
48 |
49 | if (log.type === `rename`) {
50 | // If this path already contains a rename, ignore this
51 | if (this.logs[path].some(l => l.type === `rename`)) return;
52 | }
53 |
54 | this.logs[path].push(log);
55 | }
56 |
57 | exists(path: string, type: LogType) {
58 | return this.logs[path] && this.logs[path].some(l => l.type === type)
59 | }
60 |
61 | getAllLogs() {
62 | return this.logs;
63 | }
64 |
65 | getLogsFor(path: string): FileLog[]|undefined {
66 | return this.logs[path];
67 | }
68 | }
--------------------------------------------------------------------------------
/cli/test/mixedCaseExport.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { ILEObject, Targets } from '../src/targets'
4 | import { setupFixture } from './fixtures/projects';
5 | import { ReadFileSystem } from '../src/readFileSystem';
6 |
7 | async function setupScopeAnalysis(targets: Targets) {
8 | await targets.loadProject();
9 |
10 | expect(targets.getTargets().length).toBeGreaterThan(0);
11 | targets.resolveBinder();
12 | }
13 |
14 | describe(`pr with mixed case exports exports `, () => {
15 | const project = setupFixture(`mixedCaseExport`);
16 |
17 | const fs = new ReadFileSystem();
18 | const targets = new Targets(project.cwd, fs);
19 |
20 | beforeAll(async () => {
21 | project.setup();
22 | await setupScopeAnalysis(targets);
23 | });
24 |
25 | test(`Correct check exports no matter the casing`, async () => {
26 | const allLogs = targets.logger.getAllLogs();
27 |
28 | const [srvPgmObj] = targets.getResolvedObjects(`SRVPGM`);
29 | expect(srvPgmObj).toBeDefined();
30 | expect(srvPgmObj.systemName).toBe(`MODEXCEPT`);
31 | expect(srvPgmObj.type).toBe(`SRVPGM`);
32 |
33 | const srvPgmTarget = targets.getTarget({ systemName: `MODEXCEPT`, type: `SRVPGM` });
34 | expect(srvPgmTarget).toBeDefined();
35 |
36 | expect(srvPgmTarget.deps.length).toBe(1);
37 |
38 | expect(srvPgmTarget.functions.length).toBe(3);
39 |
40 | const exportsOf = (theObject: ILEObject) => {
41 | return theObject.functions.filter(f => f.export).map(f => f.name);
42 | }
43 |
44 | expect(exportsOf(srvPgmTarget)).toStrictEqual(exportsOf(srvPgmTarget.deps[0]));
45 |
46 | expect(allLogs[srvPgmObj.relativePath].length).toBe(0);
47 | });
48 | });
--------------------------------------------------------------------------------
/cli/src/builders/iProject.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import { ObjectType } from "../targets";
3 | import { CommandParameters, CompileAttribute, getDefaultCompiles } from "./environment";
4 |
5 | export class iProject {
6 | includePaths?: string[] = [];
7 | compiles?: CompileAttribute = getDefaultCompiles();
8 | objectAttributes?: {
9 | [object: string]: CommandParameters
10 | } = {};
11 | binders?: string[] = [];
12 |
13 | constructor() {
14 |
15 | }
16 |
17 | getCompileDataForType(type: ObjectType) {
18 | return Object.values(this.compiles).find(data => data.becomes === type);
19 | }
20 |
21 | getCompileDataForSource(relativePath: string) {
22 | const parseA = path.parse(relativePath);
23 | let ext = parseA.ext.toLowerCase();
24 |
25 |
26 | if (parseA.name.includes(`.`)) {
27 | const parseB = path.parse(parseA.name);
28 | ext = parseB.ext.toLowerCase() + ext;
29 | }
30 |
31 | if (ext.startsWith(`.`)) {
32 | ext = ext.substring(1);
33 | }
34 |
35 | return this.compiles[ext];
36 | }
37 |
38 | applySettings(input: Partial) {
39 | if (input.includePaths && input.includePaths.length > 0) {
40 | this.includePaths = input.includePaths;
41 | }
42 |
43 | if (input.binders && input.binders.length > 0) {
44 | this.binders = input.binders;
45 | }
46 |
47 | if (input.compiles) {
48 | for (const [ext, data] of Object.entries(input.compiles)) {
49 | // We don't want to fully overwrite the default settings,
50 | // perhaps the user is only changing the `dir`?
51 | this.compiles[ext] = {
52 | ...(this.compiles[ext] || {}),
53 | ...data
54 | };
55 | }
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/vs/client/src/views/projectExplorer/ileObjectTreeItem.ts:
--------------------------------------------------------------------------------
1 | import { ILEObject } from "@ibm/sourceorbit/dist/src/targets";
2 | import { ProjectExplorerTreeItem } from "@ibm/vscode-ibmi-projectexplorer-types/views/projectExplorer/projectExplorerTreeItem";
3 | import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri, WorkspaceFolder } from "vscode";
4 | import { LanguageClientManager } from '../../languageClientManager';
5 | import { TypeIcons } from '../utils';
6 | import { NoticeTreeItem } from './noticeTreeItem';
7 | import path = require('path');
8 |
9 | export class ILEObjectTreeItem extends TreeItem implements ProjectExplorerTreeItem {
10 | constructor(public workspaceFolder: WorkspaceFolder, private ileObject: ILEObject, canExpand = false) {
11 | super(`${ileObject.systemName}.${ileObject.type}`, canExpand ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None);
12 | // const logs = TargetsManager.getLogs(workspaceFolder, ileObject);
13 |
14 | this.description = [ileObject.text, ileObject.extension ? `(${ileObject.extension})` : undefined].join(` `);
15 | this.iconPath = new ThemeIcon(TypeIcons[ileObject.type] || `unverified`);
16 | this.contextValue = `ileObject`;
17 |
18 | if (ileObject.relativePath) {
19 | this.resourceUri = Uri.from({ scheme: `file`, path: path.join(this.workspaceFolder.uri.fsPath, ileObject.relativePath) });
20 | }
21 | }
22 |
23 | async getChildren(): Promise<(ILEObjectTreeItem | NoticeTreeItem)[]> {
24 | const deps = await LanguageClientManager.getDeps(this.workspaceFolder, this.ileObject);
25 | if (deps.length > 0) {
26 | return deps.map(d => new ILEObjectTreeItem(this.workspaceFolder, d, false));
27 | } else {
28 | return [new NoticeTreeItem(this.workspaceFolder, `No dependencies`)];
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/vs/client/src/views/impactView/index.ts:
--------------------------------------------------------------------------------
1 | import { Event, EventEmitter, TreeDataProvider, TreeItem, Uri, workspace } from "vscode";
2 | import { LanguageClientManager } from '../../languageClientManager';
3 | import { ILEImpactedObjectTreeItem } from './ileImpactedObjectTreeItem';
4 |
5 | export class ImpactView implements TreeDataProvider {
6 | private _onDidChangeTreeData: EventEmitter = new EventEmitter();
7 | readonly onDidChangeTreeData: Event = this._onDidChangeTreeData.event;
8 | public impactOf: Uri[] = [];
9 |
10 | refresh() {
11 | this._onDidChangeTreeData.fire();
12 | }
13 |
14 | getTreeItem(element: any): TreeItem | Thenable {
15 | return element;
16 | }
17 |
18 | showImpactFor(uris: Uri[]) {
19 | this.impactOf = uris;
20 | this.refresh();
21 | }
22 |
23 | async getChildren(element?: ILEImpactedObjectTreeItem): Promise<(ILEImpactedObjectTreeItem | TreeItem)[]> {
24 | if (element && element.getChildren) {
25 | return element.getChildren();
26 | } else if (this.impactOf && this.impactOf.length > 0) {
27 | const workspaceFolder = workspace.getWorkspaceFolder(this.impactOf[0]);
28 |
29 | if (workspaceFolder) {
30 | const isProjectReady = await LanguageClientManager.isReady(workspaceFolder);
31 | if (!isProjectReady) {
32 | await LanguageClientManager.reloadProject(workspaceFolder);
33 | }
34 |
35 | const impacts = await LanguageClientManager.getImpacts(workspaceFolder, this.impactOf);
36 | if (impacts.length > 0) {
37 | return impacts.map(i => new ILEImpactedObjectTreeItem(workspaceFolder, i));
38 | } else {
39 | return [new TreeItem(`No impacted objects`)];
40 | }
41 | }
42 | }
43 |
44 | return [];
45 | }
46 | }
--------------------------------------------------------------------------------
/vs/server/src/requests.ts:
--------------------------------------------------------------------------------
1 | import { Connection } from 'vscode-languageserver';
2 | import { TargetsManager } from './TargetsManager';
3 |
4 | import { ILEObject, TargetSuggestions } from "@ibm/sourceorbit/dist/src/targets";
5 | import { URI } from 'vscode-uri';
6 | import { fixProject, generateBuildFile, initAndRefresh } from './setup';
7 |
8 | export function setupRequestHandler(connection: Connection) {
9 | connection.onRequest(`isReady`, async (params: [string]) => {
10 | return TargetsManager.isReady(params[0]);
11 | });
12 |
13 | connection.onRequest(`getResolvedObjects`, async (params: [string]) => {
14 | return TargetsManager.getResolvedObjects(params[0]);
15 | });
16 |
17 | connection.onRequest(`getDeps`, async (params: [string, ILEObject]) => {
18 | return TargetsManager.getDepsForTarget(params[0], params[1]);
19 | });
20 |
21 | connection.onRequest(`getImpacts`, async (params: [string, string[]]) => {
22 | const target = TargetsManager.getTargetsForWorkspaceUri(params[0]);
23 |
24 | if (target) {
25 | const uris = params[1];
26 |
27 | const possibleObjects = uris
28 | .map(fileUri => target.getResolvedObject(URI.parse(fileUri).fsPath.replace(/\\/g, '/')))
29 | .filter(x => x && x.relativePath);
30 |
31 | return possibleObjects.map(ileObject => target.getImpactFor(ileObject));
32 | }
33 |
34 | return [];
35 | });
36 |
37 | connection.onRequest(`reloadProject`, (params: [string]) => {
38 | return initAndRefresh(params[0]);
39 | });
40 |
41 | connection.onRequest(`fixProject`, (params: [string, keyof TargetSuggestions]) => {
42 | const suggestions: TargetSuggestions = {};
43 |
44 | suggestions[params[1]] = true;
45 |
46 | return fixProject(params[0], suggestions);
47 | });
48 |
49 | connection.onRequest(`generateBuildFile`, (params: [string, string]) => {
50 | return generateBuildFile(params[0], params[1]);
51 | });
52 | }
--------------------------------------------------------------------------------
/cli/test/includeMismatchFix.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import path from 'path';
5 | import { setupFixture } from './fixtures/projects';
6 | import { ReadFileSystem } from '../src/readFileSystem';
7 |
8 | // This issue was occuring when you had two files with the same name, but different extensions.
9 |
10 | describe(`include_mismatch_fix tests`, () => {
11 | const project = setupFixture(`include_mismatch_fix`);
12 |
13 | const fs = new ReadFileSystem();
14 | const targets = new Targets(project.cwd, fs);
15 | targets.setSuggestions({renames: true, includes: true})
16 |
17 | beforeAll(async () => {
18 | project.setup();
19 | await targets.loadProject();
20 |
21 | expect(targets.getTargets().length).toBeGreaterThan(0);
22 | targets.resolveBinder();
23 | });
24 |
25 | test(`Ensure rename is against correct file`, async () => {
26 | const articlePf = targets.getTarget({systemName: `ARTICLE`, type: `FILE`});
27 | expect(articlePf).toBeDefined();
28 |
29 | const articlePfLogs = targets.logger.getLogsFor(path.join(`QDDSSRC`, `ARTICLE.PF`));
30 | expect(articlePfLogs.length).toBe(1);
31 | expect(articlePfLogs[0].message).toBe(`no object found for reference 'SAMREF'`);
32 | expect(articlePfLogs[0].type).toBe(`warning`);
33 |
34 | const articleIncludeLogs = targets.logger.getLogsFor(path.join(`QPROTOSRC`, `ARTICLE.RPGLE`));
35 | expect(articleIncludeLogs.length).toBe(1);
36 | expect(articleIncludeLogs[0].message).toBe(`Rename suggestion`);
37 | expect(articleIncludeLogs[0].type).toBe(`rename`);
38 | expect(articleIncludeLogs[0].change).toMatchObject({
39 | rename: {
40 | path: path.join(project.cwd, `QPROTOSRC`, `ARTICLE.RPGLE`),
41 | newName: 'ARTICLE.rpgleinc'
42 | }
43 | })
44 | });
45 | });
--------------------------------------------------------------------------------
/cli/test/fixtures/projects.ts:
--------------------------------------------------------------------------------
1 | import * as fs from "fs";
2 | import * as path from "path";
3 |
4 | const projectFolder = path.join(__dirname, `..`, `..`, `..`, `testData`);
5 |
6 | export function getAllFixtures(): string[] {
7 | const dirs = fs.readdirSync(__dirname, {withFileTypes: true})
8 | .filter(dirent => dirent.isDirectory())
9 | .map(dirent => dirent.name);
10 |
11 | return dirs;
12 | }
13 |
14 | export function setupFixture(folderName: string): {cwd: string, setup: () => void, copy: () => void} {
15 | const fixturePath = path.join(__dirname, folderName);
16 | const projectPath = path.join(projectFolder, folderName);
17 |
18 | return {
19 | cwd: projectPath,
20 | setup: () => {
21 | // fs.cpSync(fixturePath, projectPath, {recursive: true});
22 | },
23 | copy: () => {
24 | deleteDir(projectPath);
25 | mkdir(projectPath);
26 | fs.cpSync(fixturePath, projectPath, {recursive: true});
27 | }
28 | };
29 | }
30 |
31 | export function createTestBuildScript() {
32 | const lines = [
33 | `# First build company system`,
34 | `system -qi "DLTLIB LIB(CMPSYSTST)"`,
35 | `cd company_system`,
36 | `gmake BIN_LIB=CMPSYSTST`,
37 | ``,
38 | `# Then build multi module`,
39 | `cd ../multi_module`,
40 | `system -qi "DLTLIB LIB(CMPSYSTST)"`,
41 | `gmake BIN_LIB=MMODTEST`,
42 | ``,
43 | `# Cleanup`,
44 | `system -qi "DLTLIB LIB(CMPSYSTST)"`,
45 | `system -qi "DLTLIB LIB(MMODTEST)"`
46 | ].join(`\n`);
47 |
48 | mkdir(projectFolder);
49 | const scriptPath = path.join(projectFolder, `build.sh`);
50 | fs.writeFileSync(scriptPath, lines);
51 | }
52 |
53 | function mkdir(dirPath: string) {
54 | try {
55 | fs.mkdirSync(dirPath, {recursive: true});
56 | } catch (e) {};
57 | }
58 |
59 | function deleteDir(dirPath: string) {
60 | try {
61 | fs.rmSync(dirPath, {recursive: true, force: true});
62 | } catch (e) {};
63 | }
--------------------------------------------------------------------------------
/cli/webpack.config.js:
--------------------------------------------------------------------------------
1 | /*---------------------------------------------------------------------------------------------
2 | * Copyright (c) Microsoft Corporation. All rights reserved.
3 | * Licensed under the MIT License. See License.txt in the project root for license information.
4 | *--------------------------------------------------------------------------------------------*/
5 |
6 | // @ts-nocheck
7 |
8 | 'use strict';
9 |
10 | const path = require(`path`);
11 | const webpack = require(`webpack`);
12 |
13 | /** @typedef {import('webpack').Configuration} WebpackConfig **/
14 |
15 | /**@type WebpackConfig*/
16 | module.exports = {
17 | mode: `none`, // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
18 | target: `node`, // extensions run in a node context
19 | node: {
20 | __dirname: false // leave the __dirname-behaviour intact
21 | },
22 | context: path.join(__dirname),
23 | resolve: {
24 | // Add `.ts` as a resolvable extension.
25 | extensions: [".ts", ".js"],
26 | // Add support for TypeScripts fully qualified ESM imports.
27 | extensionAlias: {
28 | ".js": [".js", ".ts"],
29 | ".cjs": [".cjs", ".cts"],
30 | ".mjs": [".mjs", ".mts"]
31 | }
32 | },
33 | module: {
34 | rules: [
35 | // all files with a `.ts`, `.cts`, `.mts` or `.tsx` extension will be handled by `ts-loader`
36 | { test: /\.([cm]?ts|tsx)$/, loader: "ts-loader", options: {allowTsInNodeModules: true} }
37 | ]
38 | },
39 | entry: {
40 | extension: `./src/index.ts`,
41 | },
42 | output: {
43 | filename: path.join(`index.js`),
44 | path: path.join(__dirname, `dist`),
45 | library: {
46 | "type": "commonjs"
47 | }
48 | },
49 | // yes, really source maps
50 | devtool: `source-map`,
51 | plugins: [
52 | new webpack.BannerPlugin({banner: `#! /usr/bin/env node`, raw: true})
53 | ]
54 | };
--------------------------------------------------------------------------------
/cli/test/sqlLongNames.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import { setupFixture } from './fixtures/projects';
5 | import { ReadFileSystem } from '../src/readFileSystem';
6 |
7 | // This issue was occuring when you had two files with the same name, but different extensions.
8 |
9 | describe(`sql long name lookup`, () => {
10 | const project = setupFixture(`sql_long_names`);
11 |
12 | const fs = new ReadFileSystem();
13 | const targets = new Targets(project.cwd, fs);
14 | targets.setSuggestions({ renames: true, includes: true })
15 |
16 | beforeAll(async () => {
17 | project.setup();
18 | await targets.loadProject();
19 |
20 | expect(targets.getTargets().length).toBeGreaterThan(0);
21 | targets.resolveBinder();
22 | });
23 |
24 | test(`Ensure objects are defined`, async () => {
25 | expect(targets.getTargets().length).toBe(2);
26 | expect(targets.getResolvedObjects(`FILE`).length).toBe(1);
27 | expect(targets.getResolvedObjects(`MODULE`).length).toBe(1);
28 | expect(targets.binderRequired()).toBe(false);
29 |
30 | const trans = targets.searchForObject({ systemName: `TRANS`, type: `FILE` });
31 | expect(trans).toBeDefined();
32 |
33 | const transaction = targets.searchForObject({ systemName: `TRANSACTION`, type: `FILE` });
34 | expect(transaction).toBeDefined();
35 |
36 | expect(trans).toMatchObject(transaction);
37 |
38 | const moduleLogs = targets.logger.getLogsFor(trans.relativePath);
39 | expect(moduleLogs).toBeUndefined();
40 | });
41 |
42 | test(`Ensure deps are correct`, async () => {
43 | const trans = targets.getTarget({ systemName: `DB`, type: `MODULE` });
44 | expect(trans).toBeDefined();
45 |
46 | expect(trans.deps.length).toBe(1);
47 | expect(trans.deps[0].systemName).toBe(`TRANS`);
48 | expect(trans.deps[0].longName).toBe(`TRANSACTION`);
49 | });
50 |
51 | });
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qddssrc/depts.dspf:
--------------------------------------------------------------------------------
1 | A INDARA
2 | A CA03(03)
3 | A R SFLDTA SFL
4 | A RRN 4Y 0H
5 | A* DISPLAY DTA
6 | A XSEL 1A B 7 8
7 | A XID 3A O 7 12
8 | A XNAME 38A O 7 16
9 | A* COLOR HELLO
10 | A R SFLCTL SFLCTL(SFLDTA)
11 | A SFLPAG(0014)
12 | A SFLSIZ(9999)
13 | A OVERLAY
14 | A 85 SFLDSPCTL
15 | A 95 SFLDSP
16 | A N85 SFLCLR
17 | A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
18 | A*
19 | A 6 6'Opt'
20 | A DSPATR(HI)
21 | A DSPATR(UL)
22 | A 6 12'ID'
23 | A DSPATR(HI)
24 | A DSPATR(UL)
25 | A 6 16'Name'
26 | A DSPATR(UL)
27 | A COLOR(WHT)
28 | A R FOOTER_FMT
29 | A OVERLAY
30 | A 3 6'F3=Exit'
31 | A COLOR(BLU)
32 | A 2 35'Departments'
33 | A DSPATR(UL)
34 | A COLOR(WHT)
35 | A 4 6'5=View'
36 | A COLOR(BLU)
37 |
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qddssrc/depts.dspf:
--------------------------------------------------------------------------------
1 | A INDARA
2 | A CA03(03)
3 | A R SFLDTA SFL
4 | A RRN 4Y 0H
5 | A* DISPLAY DTA
6 | A XSEL 1A B 7 8
7 | A XID 3A O 7 12
8 | A XNAME 38A O 7 16
9 | A* COLOR HELLO
10 | A R SFLCTL SFLCTL(SFLDTA)
11 | A SFLPAG(0014)
12 | A SFLSIZ(9999)
13 | A OVERLAY
14 | A 85 SFLDSPCTL
15 | A 95 SFLDSP
16 | A N85 SFLCLR
17 | A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
18 | A*
19 | A 6 6'Opt'
20 | A DSPATR(HI)
21 | A DSPATR(UL)
22 | A 6 12'ID'
23 | A DSPATR(HI)
24 | A DSPATR(UL)
25 | A 6 16'Name'
26 | A DSPATR(UL)
27 | A COLOR(WHT)
28 | A R FOOTER_FMT
29 | A OVERLAY
30 | A 3 6'F3=Exit'
31 | A COLOR(BLU)
32 | A 2 35'Departments'
33 | A DSPATR(UL)
34 | A COLOR(WHT)
35 | A 4 6'5=View'
36 | A COLOR(BLU)
37 |
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qddssrc/depts.dspf:
--------------------------------------------------------------------------------
1 | A INDARA
2 | A CA03(03)
3 | A R SFLDTA SFL
4 | A RRN 4Y 0H
5 | A* DISPLAY DTA
6 | A XSEL 1A B 7 8
7 | A XID 3A O 7 12
8 | A XNAME 38A O 7 16
9 | A* COLOR HELLO
10 | A R SFLCTL SFLCTL(SFLDTA)
11 | A SFLPAG(0014)
12 | A SFLSIZ(9999)
13 | A OVERLAY
14 | A 85 SFLDSPCTL
15 | A 95 SFLDSP
16 | A N85 SFLCLR
17 | A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
18 | A*
19 | A 6 6'Opt'
20 | A DSPATR(HI)
21 | A DSPATR(UL)
22 | A 6 12'ID'
23 | A DSPATR(HI)
24 | A DSPATR(UL)
25 | A 6 16'Name'
26 | A DSPATR(UL)
27 | A COLOR(WHT)
28 | A R FOOTER_FMT
29 | A OVERLAY
30 | A 3 6'F3=Exit'
31 | A COLOR(BLU)
32 | A 2 35'Departments'
33 | A DSPATR(UL)
34 | A COLOR(WHT)
35 | A 4 6'5=View 8=New Employee'
36 | A COLOR(BLU)
37 |
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qddssrc/depts.dspf:
--------------------------------------------------------------------------------
1 | A INDARA
2 | A CA03(03)
3 | A R SFLDTA SFL
4 | A RRN 4Y 0H
5 | A* DISPLAY DTA
6 | A XSEL 1A B 7 8
7 | A XID 3A O 7 12
8 | A XNAME 38A O 7 16
9 | A* COLOR HELLO
10 | A R SFLCTL SFLCTL(SFLDTA)
11 | A SFLPAG(0014)
12 | A SFLSIZ(9999)
13 | A OVERLAY
14 | A 85 SFLDSPCTL
15 | A 95 SFLDSP
16 | A N85 SFLCLR
17 | A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
18 | A*
19 | A 6 6'Opt'
20 | A DSPATR(HI)
21 | A DSPATR(UL)
22 | A 6 12'ID'
23 | A DSPATR(HI)
24 | A DSPATR(UL)
25 | A 6 16'Name'
26 | A DSPATR(UL)
27 | A COLOR(WHT)
28 | A R FOOTER_FMT
29 | A OVERLAY
30 | A 3 6'F3=Exit'
31 | A COLOR(BLU)
32 | A 2 35'Departments'
33 | A DSPATR(UL)
34 | A COLOR(WHT)
35 | A 4 6'5=View 8=New Employee'
36 | A COLOR(BLU)
37 |
--------------------------------------------------------------------------------
/vs/server/src/server.ts:
--------------------------------------------------------------------------------
1 | import { Targets } from '@ibm/sourceorbit';
2 | import {
3 | createConnection,
4 | InitializeParams,
5 | InitializeResult,
6 | ProposedFeatures,
7 | TextDocumentSyncKind
8 | } from 'vscode-languageserver/node';
9 | import { setupFsListener } from './fileSystemListener';
10 | import { setupRequestHandler } from './requests';
11 |
12 | // Create a connection for the server, using Node's IPC as a transport.
13 | // Also include all preview / proposed LSP features.
14 | export const connection = createConnection(ProposedFeatures.all);
15 |
16 | let hasWorkspaceFolderCapability = false;
17 |
18 | connection.onInitialize((params: InitializeParams) => {
19 | const capabilities = params.capabilities;
20 |
21 | // Does the client support the `workspace/configuration` request?
22 | // If not, we fall back using global settings.
23 | hasWorkspaceFolderCapability = !!(
24 | capabilities.workspace && !!capabilities.workspace.workspaceFolders
25 | );
26 |
27 | const result: InitializeResult = {
28 | capabilities: {
29 | textDocumentSync: TextDocumentSyncKind.Incremental,
30 | }
31 | };
32 | if (hasWorkspaceFolderCapability) {
33 | result.capabilities.workspace = {
34 | fileOperations: {
35 | didCreate: { filters: [{ pattern: { glob: Targets.LanguageProvider.getGlob(), options: { ignoreCase: true } } }] },
36 | didRename: { filters: [{ pattern: { glob: Targets.LanguageProvider.getGlob(), options: { ignoreCase: true } } }] },
37 | didDelete: { filters: [{ pattern: { glob: Targets.LanguageProvider.getGlob(), options: { ignoreCase: true } } }] }
38 | },
39 | workspaceFolders: {
40 | supported: true,
41 | changeNotifications: true
42 | }
43 | };
44 | }
45 | return result;
46 | });
47 |
48 |
49 | connection.onInitialized(() => {
50 | if (hasWorkspaceFolderCapability) {
51 | setupFsListener(connection);
52 | }
53 | });
54 |
55 | // Listen on the connection
56 | connection.listen();
57 |
58 | setupRequestHandler(connection);
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qddssrc/emps.dspf:
--------------------------------------------------------------------------------
1 | A INDARA
2 | A CA12(12)
3 | A R SFLDTA SFL
4 | A RRN 4Y 0H
5 | A* DISPLAY DTA
6 | A XSEL 1A B 7 8
7 | A XID 6A O 7 12
8 | A XNAME 30A O 7 20
9 | A XJOB 8A O 7 52
10 | A* COLOR HELLO
11 | A R SFLCTL SFLCTL(SFLDTA)
12 | A SFLPAG(0014)
13 | A SFLSIZ(9999)
14 | A OVERLAY
15 | A 85 SFLDSPCTL
16 | A 95 SFLDSP
17 | A N85 SFLCLR
18 | A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
19 | A*
20 | A 6 6'Opt'
21 | A DSPATR(HI)
22 | A DSPATR(UL)
23 | A 6 12'ID'
24 | A DSPATR(HI)
25 | A DSPATR(UL)
26 | A 6 20'Name'
27 | A DSPATR(UL)
28 | A COLOR(WHT)
29 | A 6 52'Job'
30 | A DSPATR(UL)
31 | A COLOR(WHT)
32 | A R FOOTER_FMT
33 | A OVERLAY
34 | A 3 06'F12=Back'
35 | A COLOR(BLU)
36 | A 2 35'Employees'
37 | A DSPATR(UL)
38 |
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qddssrc/emps.dspf:
--------------------------------------------------------------------------------
1 | A INDARA
2 | A CA12(12)
3 | A R SFLDTA SFL
4 | A RRN 4Y 0H
5 | A* DISPLAY DTA
6 | A XSEL 1A B 7 8
7 | A XID 6A O 7 12
8 | A XNAME 30A O 7 20
9 | A XJOB 8A O 7 52
10 | A* COLOR HELLO
11 | A R SFLCTL SFLCTL(SFLDTA)
12 | A SFLPAG(0014)
13 | A SFLSIZ(9999)
14 | A OVERLAY
15 | A 85 SFLDSPCTL
16 | A 95 SFLDSP
17 | A N85 SFLCLR
18 | A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
19 | A*
20 | A 6 6'Opt'
21 | A DSPATR(HI)
22 | A DSPATR(UL)
23 | A 6 12'ID'
24 | A DSPATR(HI)
25 | A DSPATR(UL)
26 | A 6 20'Name'
27 | A DSPATR(UL)
28 | A COLOR(WHT)
29 | A 6 52'Job'
30 | A DSPATR(UL)
31 | A COLOR(WHT)
32 | A R FOOTER_FMT
33 | A OVERLAY
34 | A 3 06'F12=Back'
35 | A COLOR(BLU)
36 | A 2 35'Employees'
37 | A DSPATR(UL)
38 |
--------------------------------------------------------------------------------
/vs/shared.webpack.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable @typescript-eslint/no-var-requires */
3 | /*---------------------------------------------------------------------------------------------
4 | * Copyright (c) Microsoft Corporation. All rights reserved.
5 | * Licensed under the MIT License. See License.txt in the project root for license information.
6 | *--------------------------------------------------------------------------------------------*/
7 |
8 | //@ts-check
9 | /** @typedef {import('webpack').Configuration} WebpackConfig **/
10 |
11 | 'use strict';
12 |
13 | const path = require(`path`);
14 | const merge = require(`merge-options`);
15 |
16 | module.exports = function withDefaults(/**@type WebpackConfig*/extConfig) {
17 |
18 | /** @type WebpackConfig */
19 | let defaultConfig = {
20 | mode: `none`, // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
21 | target: `node`, // extensions run in a node context
22 | node: {
23 | __dirname: false // leave the __dirname-behaviour intact
24 | },
25 | resolve: {
26 | mainFields: [`module`, `main`],
27 | extensions: [`.ts`, `.js`] // support ts-files and js-files
28 | },
29 | module: {
30 | rules: [{
31 | test: /\.ts$/,
32 | exclude: /node_modules/,
33 | use: [{
34 | // configure TypeScript loader:
35 | // * enable sources maps for end-to-end source maps
36 | loader: `esbuild-loader`
37 | }]
38 | }]
39 | },
40 | externals: {
41 | 'vscode': `commonjs vscode`, // ignored because it doesn't exist
42 | },
43 | output: {
44 | // all output goes into `dist`.
45 | // packaging depends on that and this must always be like it
46 | filename: `[name].js`,
47 | path: path.join(String(extConfig.context), `out`),
48 | libraryTarget: `commonjs`,
49 | },
50 | // yes, really source maps
51 | devtool: `source-map`
52 | };
53 |
54 | return merge(defaultConfig, extConfig);
55 | };
--------------------------------------------------------------------------------
/vs/client/src/git/index.ts:
--------------------------------------------------------------------------------
1 | import { Uri, WorkspaceFolder, extensions } from 'vscode';
2 | import { API, Change, GitExtension, Status } from './git';
3 |
4 | let gitLookedUp: boolean;
5 | let gitAPI: API | undefined;
6 |
7 | export const lastBranch: {[workspaceUri: string]: string} = {};
8 |
9 | export function getGitAPI(): API | undefined {
10 | if (!gitLookedUp) {
11 | try {
12 | gitAPI = extensions.getExtension(`vscode.git`)?.exports.getAPI(1);
13 | }
14 | catch (error) {
15 | console.log(`Git extension issue.`, error);
16 | }
17 | finally {
18 | gitLookedUp = true;
19 | }
20 | }
21 | return gitAPI;
22 | }
23 |
24 | export async function getDeployGitFiles(workspaceFolder: WorkspaceFolder, changeType: 'staged' | 'working' | 'both' = 'both'): Promise {
25 | const gitApi = getGitAPI();
26 |
27 | if (gitApi && gitApi.repositories.length > 0) {
28 | const repository = gitApi.repositories.find(r => r.rootUri.fsPath === workspaceFolder.uri.fsPath);
29 |
30 | if (repository) {
31 | const staged = repository.state.indexChanges;
32 | const working = repository.state.workingTreeChanges;
33 |
34 | let gitFiles: Change[];
35 |
36 | switch (changeType) {
37 | case `both`:
38 | gitFiles = [...staged, ...working];
39 | break;
40 | case `staged`:
41 | gitFiles = staged;
42 | break;
43 | case `working`:
44 | gitFiles = working;
45 | break;
46 | }
47 |
48 | // Do not attempt to upload deleted files.
49 | // https://github.com/microsoft/vscode/blob/main/extensions/git/src/api/git.d.ts#L69
50 | gitFiles = gitFiles.filter(change => change.status !== Status.DELETED);
51 |
52 | if (gitFiles.length > 0) {
53 | const uris = gitFiles.map(change => change.uri);
54 | const unique = uris.filter((value, index, array) => array.findIndex(u => u.toString() === value.toString()) === index);
55 | return unique;
56 | } else {
57 | return [];
58 | }
59 | } else {
60 | throw new Error(`No repository found for ${workspaceFolder.uri.fsPath}`);
61 | }
62 | } else {
63 | throw new Error(`No repositories are open.`);
64 | }
65 | }
--------------------------------------------------------------------------------
/cli/test/bobWithExistingFiles.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import path from 'path';
5 | import { setupFixture } from './fixtures/projects';
6 | import { BobProject } from '../src';
7 | import { ReadFileSystem } from '../src/readFileSystem';
8 |
9 | // This issue was occuring when you had two files with the same name, but different extensions.
10 |
11 | describe(`bob Rules.mk tests`, () => {
12 | const project = setupFixture(`pseudo`);
13 |
14 | const fs = new ReadFileSystem();
15 | const targets = new Targets(project.cwd, fs);
16 | targets.setSuggestions({ renames: true, includes: true })
17 |
18 | beforeAll(async () => {
19 | project.setup();
20 | await targets.loadProject();
21 |
22 | expect(targets.getTargets().length).toBeGreaterThan(0);
23 | targets.resolveBinder();
24 | });
25 |
26 | test(`bob to not overwrite any pre-existing rules for targets`, () => {
27 | const project = new BobProject(targets);
28 |
29 | const files = project.createRules();
30 |
31 | const baseRules = files[`Rules.mk`].split(/\r?\n/);
32 |
33 | expect(baseRules).toBeDefined();
34 | expect(baseRules[0]).toContain(`SUBDIRS =`);
35 | expect(baseRules[0]).toContain(`qobjs`);
36 | expect(baseRules[0]).toContain(`qrpglesrc`);
37 |
38 | const qobjRules = files[path.join(`qobjs`, `Rules.mk`)].split(/\r?\n/);
39 |
40 | expect(qobjRules).toBeDefined();
41 | expect(qobjRules).toContain(`MYTHING.DTAARA:text=Hello world`);
42 | expect(qobjRules).toContain(`MSTDSP.FILE: mstdsp.dspf`);
43 |
44 | const qrpglesrcRules = files[path.join(`qrpglesrc`, `Rules.mk`)].split(/\r?\n/);
45 |
46 | expect(qrpglesrcRules).toBeDefined();
47 | expect(qrpglesrcRules).toContain(`TESTER.PGM: tester.pgm.rpgle MYTHING.DTAARA`);
48 | expect(qrpglesrcRules).toContain(`TESTER.PGM: text = My program`);
49 | expect(qrpglesrcRules).toContain(`# Other assignment`);
50 | expect(qrpglesrcRules).toContain(`TESTER.PGM: bnddir:=MYBND`);
51 | expect(qrpglesrcRules).toContain(`OTHER.PGM: other.pgm.sqlrpgle MSTDSP.FILE`);
52 | });
53 | });
--------------------------------------------------------------------------------
/cli/test/overrideObjRef.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import path from 'path';
5 | import { setupFixture } from './fixtures/projects';
6 | import { referencesFileName } from '../src/extensions';
7 | import { ReadFileSystem } from '../src/readFileSystem';
8 |
9 | const cwd = setupFixture(`override_objref`);
10 |
11 | // This issue was occuring when you had two files with the same name, but different extensions.
12 |
13 | describe(`ensure that objrefs can be overridden`, () => {
14 | const project = setupFixture(`override_objref`);
15 |
16 | const fs = new ReadFileSystem();
17 | const targets = new Targets(project.cwd, fs);
18 | targets.setSuggestions({renames: true, includes: true})
19 |
20 | test(`Ensure objects are defined`, async () => {
21 | await targets.handleRefsFile(path.join(project.cwd, referencesFileName));
22 | expect(targets.getResolvedObjects().length).toBe(1);
23 | expect(targets.getTargets().length).toBe(0);
24 |
25 | await targets.loadProject();
26 |
27 | expect(targets.getTargets().length).toBeGreaterThan(0);
28 | targets.resolveBinder();
29 |
30 | expect(targets.getTargets().length).toBe(4);
31 |
32 | expect(targets.getResolvedObjects().length).toBe(4);
33 | expect(targets.getResolvedObjects(`FILE`).length).toBe(4);
34 |
35 | expect(targets.binderRequired()).toBe(false);
36 |
37 | const pro250d = targets.searchForObject({systemName: `PRO250D`, type: `FILE`});
38 | expect(pro250d).toBeDefined();
39 | expect(pro250d.reference).toBeUndefined();
40 |
41 | const provider = targets.searchForObject({systemName: `PROVIDER`, type: `FILE`});
42 | expect(provider).toBeDefined();
43 | expect(provider.reference).toBeUndefined();
44 |
45 | const provide1 = targets.searchForObject({systemName: `PROVIDE1`, type: `FILE`});
46 | expect(provide1).toBeDefined();
47 | expect(provide1.reference).toBeUndefined();
48 |
49 | const samref = targets.searchForObject({systemName: `SAMREF`, type: `FILE`});
50 | expect(samref).toBeDefined();
51 | expect(samref.reference).toBeUndefined();
52 | });
53 | });
--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: Release CLI and Extension
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | release:
7 | types: [created]
8 |
9 | jobs:
10 | cli:
11 | name: Release CLI
12 |
13 | runs-on: ubuntu-latest
14 |
15 | permissions:
16 | packages: write
17 | contents: read
18 |
19 | defaults:
20 | run:
21 | working-directory: ./cli
22 |
23 | strategy:
24 | matrix:
25 | node-version: [20.x]
26 |
27 | steps:
28 | - name: Checkout
29 | uses: actions/checkout@v4
30 |
31 | - name: Use Node.js ${{ matrix.node-version }}
32 | uses: actions/setup-node@v4
33 | with:
34 | node-version: ${{ matrix.node-version }}
35 | registry-url: 'https://registry.npmjs.org'
36 |
37 | - name: Publish CLI
38 | run: |
39 | npm ci
40 | npm run test
41 | npm run webpack
42 | npm publish --access public
43 | env:
44 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
45 |
46 | extension:
47 | name: Release Extension
48 |
49 | runs-on: ubuntu-latest
50 |
51 | permissions:
52 | packages: write
53 | contents: read
54 |
55 | defaults:
56 | run:
57 | working-directory: ./vs
58 |
59 | strategy:
60 | matrix:
61 | node-version: [20.x]
62 |
63 | steps:
64 | - name: Checkout
65 | uses: actions/checkout@v4
66 |
67 | - name: Use Node.js ${{ matrix.node-version }}
68 | uses: actions/setup-node@v4
69 | with:
70 | node-version: ${{ matrix.node-version }}
71 | registry-url: 'https://registry.npmjs.org'
72 |
73 | - name: Install NPM Dependencies
74 | run: |
75 | npm install
76 | npm install -g vsce ovsx
77 |
78 | - name: Publish to Open VSX
79 | run: npx ovsx publish -p $OPENVSX_TOKEN
80 | env:
81 | OPENVSX_TOKEN: ${{ secrets.OPENVSX_TOKEN }}
82 |
83 | - name: Publish to Marketplace
84 | run: vsce publish -p $PUBLISHER_TOKEN
85 | env:
86 | PUBLISHER_TOKEN: ${{ secrets.PUBLISHER_TOKEN }}
--------------------------------------------------------------------------------
/cli/test/fixtures/from_qsys/qsqlsrc/prjmst.table:
--------------------------------------------------------------------------------
1 | -- Project Master
2 | CREATE OR REPLACE TABLE PRJMST (
3 | -- SQL150B 10 REUSEDLT(*NO) in table PRJMST in PAYROLL1 ignored.
4 | ACREC CHAR(1) CCSID 37 NOT NULL DEFAULT '' ,
5 | PRCDE CHAR(8) CCSID 37 NOT NULL DEFAULT '' ,
6 | PRDSC CHAR(50) CCSID 37 NOT NULL DEFAULT '' ,
7 | PRRSP CHAR(30) CCSID 37 NOT NULL DEFAULT '' ,
8 | PRSTR DECIMAL(6, 0) NOT NULL DEFAULT 0 ,
9 | PREND DECIMAL(6, 0) NOT NULL DEFAULT 0 ,
10 | PRCMP DECIMAL(6, 0) NOT NULL DEFAULT 0 ,
11 | PREST DECIMAL(9, 1) NOT NULL DEFAULT 0 ,
12 | PRHRC DECIMAL(7, 1) NOT NULL DEFAULT 0 ,
13 | PRHRY DECIMAL(9, 1) NOT NULL DEFAULT 0 ,
14 | PRHRP DECIMAL(9, 1) NOT NULL DEFAULT 0 ,
15 | PRIMARY KEY( PRCDE ) )
16 |
17 | RCDFMT RCPRJ ;
18 |
19 | LABEL ON COLUMN PRJMST
20 | ( PRCDE IS 'PROJECT CODE' ,
21 | PRDSC IS 'PROJECT DESCRIPTION' ,
22 | PRRSP IS 'PROJECT RESPONSIBILITY' ,
23 | PRSTR IS 'PRJ START DATE' ,
24 | PREND IS 'PRJ EST END DATE' ,
25 | PRCMP IS 'PRJ CMP DATE' ,
26 | PREST IS 'PRJ EST TOT HRS' ,
27 | PRHRC IS 'PRJ HRS CUR MTH' ,
28 | PRHRY IS 'PRJ HRS YTD' ,
29 | PRHRP IS 'PRJ HRS PRIOR YR' ) ;
30 |
31 | LABEL ON COLUMN PRJMST
32 | ( ACREC TEXT IS 'ACTIVE RECORD CODE' ,
33 | PRCDE TEXT IS 'PROJECT CODE' ,
34 | PRDSC TEXT IS 'PROJECT DESCRIPTION' ,
35 | PRRSP TEXT IS 'PROJECT RESPONSIBILITY' ,
36 | PRSTR TEXT IS 'PROJECT START DATE' ,
37 | PREND TEXT IS 'PROJECT ESTIMATED END DATE' ,
38 | PRCMP TEXT IS 'PROJECT COMPLETION DATE' ,
39 | PREST TEXT IS 'PROJECT ESTIMATED TOTAL HRS' ,
40 | PRHRC TEXT IS 'PROJECT HOURS CURRENT MONTH' ,
41 | PRHRY TEXT IS 'PROJECT HOURS YEAR TO DATE' ,
42 | PRHRP TEXT IS 'PROJECT HOURS PRIOR YEAR' ) ;
43 |
44 | GRANT DELETE , INSERT , SELECT , UPDATE
45 | ON PRJMST TO PUBLIC ;
46 |
47 | -- GRANT ALTER , DELETE , INDEX , INSERT , REFERENCES , SELECT , UPDATE
48 | -- ON PRJMST TO WDSCTEST WITH GRANT OPTION ;
49 |
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qddssrc/emps.dspf:
--------------------------------------------------------------------------------
1 | A INDARA
2 | A CA12(12)
3 | A R SFLDTA SFL
4 | A RRN 4Y 0H
5 | A* DISPLAY DTA
6 | A XSEL 1A B 7 8
7 | A XID 6A O 7 12
8 | A XNAME 30A O 7 20
9 | A XJOB 8A O 7 52
10 | A* COLOR HELLO
11 | A R SFLCTL SFLCTL(SFLDTA)
12 | A SFLPAG(0014)
13 | A SFLSIZ(9999)
14 | A OVERLAY
15 | A 85 SFLDSPCTL
16 | A 95 SFLDSP
17 | A N85 SFLCLR
18 | A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
19 | A*
20 | A 6 6'Opt'
21 | A DSPATR(HI)
22 | A DSPATR(UL)
23 | A 6 12'ID'
24 | A DSPATR(HI)
25 | A DSPATR(UL)
26 | A 6 20'Name'
27 | A DSPATR(UL)
28 | A COLOR(WHT)
29 | A 6 52'Job'
30 | A DSPATR(UL)
31 | A COLOR(WHT)
32 | A 5 52'Total'
33 | A DSPATR(UL)
34 | A COLOR(WHT)
35 | A XTOT 9S 2O 5 61
36 | A R FOOTER_FMT
37 | A OVERLAY
38 | A 3 06'F12=Back'
39 | A COLOR(BLU)
40 | A 2 35'Employees'
41 | A DSPATR(UL)
42 |
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qddssrc/emps.dspf:
--------------------------------------------------------------------------------
1 | A INDARA
2 | A CA12(12)
3 | A R SFLDTA SFL
4 | A RRN 4Y 0H
5 | A* DISPLAY DTA
6 | A XSEL 1A B 7 8
7 | A XID 6A O 7 12
8 | A XNAME 30A O 7 20
9 | A XJOB 8A O 7 52
10 | A* COLOR HELLO
11 | A R SFLCTL SFLCTL(SFLDTA)
12 | A SFLPAG(0014)
13 | A SFLSIZ(9999)
14 | A OVERLAY
15 | A 85 SFLDSPCTL
16 | A 95 SFLDSP
17 | A N85 SFLCLR
18 | A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
19 | A*
20 | A 6 6'Opt'
21 | A DSPATR(HI)
22 | A DSPATR(UL)
23 | A 6 12'ID'
24 | A DSPATR(HI)
25 | A DSPATR(UL)
26 | A 6 20'Name'
27 | A DSPATR(UL)
28 | A COLOR(WHT)
29 | A 6 52'Job'
30 | A DSPATR(UL)
31 | A COLOR(WHT)
32 | A 5 52'Total'
33 | A DSPATR(UL)
34 | A COLOR(WHT)
35 | A XTOT 9S 2O 5 61
36 | A R FOOTER_FMT
37 | A OVERLAY
38 | A 3 06'F12=Back'
39 | A COLOR(BLU)
40 | A 2 35'Employees'
41 | A DSPATR(UL)
42 |
--------------------------------------------------------------------------------
/cli/test/multiModule.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import path from 'path';
5 | import { MakeProject } from '../src/builders/make';
6 | import { setupFixture } from './fixtures/projects';
7 | import { writeFileSync } from 'fs';
8 | import { ReadFileSystem } from '../src/readFileSystem';
9 |
10 | describe(`multi_module tests`, () => {
11 | const project = setupFixture(`multi_module`);
12 |
13 | const fs = new ReadFileSystem();
14 | const targets = new Targets(project.cwd, fs);
15 |
16 | beforeAll(async () => {
17 | project.setup();
18 | await targets.loadProject();
19 |
20 | targets.resolveBinder();
21 | });
22 |
23 | test(`Check objects are generated`, async () => {
24 | expect(targets.getResolvedObjects().length).toBe(4);
25 | expect(targets.getTargets().length).toBe(4);
26 | expect(targets.getTargetsOfType(`FILE`).length).toBe(0);
27 | expect(targets.getTargetsOfType(`PGM`).length).toBe(1);
28 | expect(targets.getTargetsOfType(`MODULE`).length).toBe(3);
29 | expect(targets.getTargetsOfType(`SRVPGM`).length).toBe(0);
30 | });
31 |
32 | test(`Check program`, async () => {
33 | const gitBrg = targets.getTarget({systemName: `GITBRG`, type: `PGM`});
34 | expect(gitBrg).toBeDefined();
35 |
36 | const deps = gitBrg.deps;
37 | expect(deps.length).toBe(2);
38 |
39 | expect(deps.find(d => d.systemName === `GITBRG` && d.type === `MODULE`)).toBeDefined();
40 | expect(deps.find(d => d.systemName === `UTILS` && d.type === `MODULE`)).toBeDefined();
41 | expect(deps.find(d => d.systemName === `OBJECTS` && d.type === `MODULE`)).toBeUndefined();
42 | });
43 |
44 | test(`Check solo module`, async () => {
45 | const objectsMod = targets.getTarget({systemName: `OBJECTS`, type: `MODULE`});
46 | expect(objectsMod).toBeDefined();
47 |
48 | expect(objectsMod.deps.length).toBe(0);
49 | });
50 |
51 | test(`Generate makefile`, async () => {
52 | const makeProj = new MakeProject(project.cwd, targets, fs);
53 | await makeProj.setupSettings();
54 |
55 | writeFileSync(path.join(project.cwd, `makefile`), makeProj.getMakefile().join(`\n`));
56 | });
57 | });
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Source Orbit Docs
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Loading...
18 |
19 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/cli/test/autofix2.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, test } from "vitest";
2 | import { setupFixture } from "./fixtures/projects";
3 |
4 | import { Targets } from '../src/targets'
5 | import { renameFiles } from "../src/utils";
6 |
7 | import * as path from "path";
8 | import { ReadFileSystem } from "../src/readFileSystem";
9 |
10 | test(`Auto rename RPGLE program and include and fix-include infos`, async () => {
11 | const project = setupFixture(`auto_rename1`);
12 | project.copy();
13 |
14 | const fs = new ReadFileSystem();
15 |
16 | // First step is to rename the files
17 | let targets = new Targets(project.cwd, fs);
18 | targets.setSuggestions({renames: true});
19 |
20 | await targets.loadProject();
21 |
22 | targets.resolveBinder();
23 |
24 | let allLogs = targets.logger.getAllLogs();
25 | expect(Object.keys(allLogs).length).toBeGreaterThan(0);
26 |
27 | const pgmSource = allLogs[path.join(`src`, `BBSADMMNUR.rpgle`)].filter(log => log.type === `rename`);
28 | const cbkSource = allLogs[path.join(`src`, `CBKOPTIMIZ.rpgle`)];
29 |
30 | expect(pgmSource.length).toBe(1);
31 | expect(cbkSource.length).toBe(1);
32 |
33 | expect(pgmSource[0].message).toBe(`Rename suggestion`);
34 | expect(pgmSource[0].type).toBe(`rename`);
35 | expect(pgmSource[0].change.rename.newName).toBe(`BBSADMMNUR.pgm.rpgle`);
36 |
37 | expect(cbkSource[0].message).toBe(`Rename suggestion`);
38 | expect(cbkSource[0].type).toBe(`rename`);
39 | expect(cbkSource[0].change.rename.newName).toBe(`CBKOPTIMIZ.rpgleinc`);
40 |
41 | // Trigger the rename
42 | renameFiles(targets.logger);
43 |
44 | // Next, scan the project again and check the logs
45 | targets = new Targets(project.cwd, fs);
46 | targets.setSuggestions({includes: true});
47 |
48 | await targets.loadProject();
49 |
50 | allLogs = targets.logger.getAllLogs();
51 |
52 | const newPgmSource = allLogs[path.join(`src`, `BBSADMMNUR.pgm.rpgle`)].filter(log => log.type === `includeFix`);
53 |
54 | expect(newPgmSource.length).toBe(1);
55 |
56 | expect(newPgmSource[0].message).toBe(`Will update to use unix style path.`);
57 | expect(newPgmSource[0].type).toBe(`includeFix`);
58 | expect(newPgmSource[0].change.lineContent).toBe(` /copy 'src/CBKOPTIMIZ.rpgleinc'`);
59 | expect(newPgmSource[0].line).toBe(11);
60 | });
61 |
--------------------------------------------------------------------------------
/vs/server/src/fileSystemListener.ts:
--------------------------------------------------------------------------------
1 | import { Connection } from 'vscode-languageserver';
2 | import { initAndRefresh } from './setup';
3 | import { TargetsManager } from './TargetsManager';
4 |
5 | export function setupFsListener(connection: Connection) {
6 |
7 | // Commented out since we don't read entire projects on load
8 | // connection.workspace.getWorkspaceFolders().then(workspaceFolders => {
9 | // connection.console.log(`Connected and got workspace folders`);
10 | // if (workspaceFolders) {
11 | // for (const workspaceFolder of workspaceFolders) {
12 | // connection.console.log(JSON.stringify(workspaceFolder, null, 2));
13 | // initAndRefresh(workspaceFolder.uri);
14 | // }
15 | // }
16 | // });
17 |
18 | connection.workspace.onDidChangeWorkspaceFolders(_event => {
19 | connection.console.log('Workspace folder change event received.');
20 | connection.console.log(JSON.stringify(_event, null, 2));
21 |
22 | for (const removed of _event.removed) {
23 | TargetsManager.destroy(removed.uri);
24 | }
25 |
26 | // Commented out since we don't read entire projects on load
27 | // for (const added of _event.added) {
28 | // initAndRefresh(added.uri);
29 | // }
30 | });
31 |
32 | connection.onDidSaveTextDocument((params) => {
33 | const uri = params.textDocument.uri;
34 | connection.console.log(JSON.stringify(uri, null, 2));
35 |
36 | TargetsManager.refreshSingle(uri);
37 | });
38 |
39 | connection.workspace.onDidDeleteFiles((params) => {
40 | const files = params.files;
41 | connection.console.log(JSON.stringify(files, null, 2));
42 |
43 | files.map(deleted => TargetsManager.removeSingle(deleted.uri));
44 |
45 | });
46 |
47 | connection.workspace.onDidCreateFiles((params) => {
48 | const files = params.files;
49 | connection.console.log(JSON.stringify(files, null, 2));
50 |
51 | for (const created of files) {
52 | TargetsManager.refreshSingle(created.uri);
53 | }
54 | });
55 |
56 | connection.workspace.onDidRenameFiles(async (params) => {
57 | const files = params.files;
58 | connection.console.log(JSON.stringify(files, null, 2));
59 |
60 | const workspaceUris: string[] = [];
61 |
62 | for (const rename of files) {
63 | await TargetsManager.removeSingle(rename.oldUri);
64 | TargetsManager.refreshSingle(rename.newUri);
65 | }
66 | });
67 | }
--------------------------------------------------------------------------------
/vs/client/src/tasks.ts:
--------------------------------------------------------------------------------
1 | import { CustomExecution, EventEmitter, ExtensionContext, Pseudoterminal, Task, TaskDefinition, TaskScope, TerminalDimensions, WorkspaceFolder, tasks } from 'vscode';
2 | import { LanguageClientManager } from './languageClientManager';
3 |
4 | export namespace SourceOrbitTask {
5 | interface SourceOrbitTask extends TaskDefinition {
6 | builder: "bob" | "make" | "imd" | "json";
7 | }
8 |
9 | export function initializeTaskProvider(context: ExtensionContext) {
10 | context.subscriptions.push(
11 | tasks.registerTaskProvider('sourceorbit', {
12 | provideTasks: () => {
13 | return [];
14 | },
15 | resolveTask(_task, _token) {
16 | const task = _task.definition as SourceOrbitTask;
17 | // A Rake task consists of a task and an optional file as specified in RakeTaskDefinition
18 | // Make sure that this looks like a Rake task by checking that there is a task.
19 | if (task) {
20 | // resolveTask requires that the same definition object be used.
21 | const workspaceFolder = _task.scope as WorkspaceFolder;
22 |
23 | return new Task(
24 | task,
25 | TaskScope.Workspace,
26 | `Source Orbit Builder`,
27 | 'sourceorbit',
28 | new CustomExecution(async (e) => {
29 | const writeEmitter = new EventEmitter();
30 | const closeEmitter = new EventEmitter();
31 |
32 | const term: Pseudoterminal = {
33 | onDidWrite: writeEmitter.event,
34 | onDidClose: closeEmitter.event,
35 | open: async (_initialDimensions: TerminalDimensions | undefined) => {
36 | writeEmitter.fire(`Generating ${task.builder} files for ${workspaceFolder.name}...\r\n`);
37 | try {
38 | await LanguageClientManager.generateBuildFile(workspaceFolder, task.builder);
39 |
40 | writeEmitter.fire(`Finished\r\n`);
41 | closeEmitter.fire(0);
42 | } catch (_e) {
43 | writeEmitter.fire(`Failed\r\n`);
44 | writeEmitter.fire(JSON.stringify(e, null, 2) + `\r\n`);
45 | closeEmitter.fire(1);
46 | }
47 | },
48 | close: function (): void { console.log(); }
49 | };
50 |
51 | return term;
52 | })
53 | );
54 | }
55 | return undefined;
56 | },
57 | })
58 | );
59 | }
60 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qddssrc/nemp.dspf:
--------------------------------------------------------------------------------
1 | A INDARA
2 | A CA12(12)
3 | A R DETAIL
4 | A 6 10'ID'
5 | A DSPATR(HI)
6 | A DSPATR(UL)
7 | A XID 6A O 6 14
8 |
9 | A 7 7'First'
10 | A DSPATR(UL)
11 | A COLOR(WHT)
12 | A XFIRST 12A B 7 14
13 |
14 | A 8 5'Initial'
15 | A DSPATR(UL)
16 | A COLOR(WHT)
17 | A XINIT 1A B 8 14
18 |
19 | A 9 8'Last'
20 | A DSPATR(UL)
21 | A COLOR(WHT)
22 | A XLAST 15A B 9 14
23 |
24 | A 10 2'Department'
25 | A DSPATR(UL)
26 | A COLOR(WHT)
27 | A XDEPT 3A O 10 14
28 |
29 | A 11 9'Job'
30 | A DSPATR(UL)
31 | A COLOR(WHT)
32 | A XJOB 8A B 11 14
33 |
34 | A 12 6'Salary'
35 | A DSPATR(UL)
36 | A COLOR(WHT)
37 | A XSAL 10A B 12 14
38 |
39 | A 13 7'Phone'
40 | A DSPATR(UL)
41 | A COLOR(WHT)
42 | A XTEL 4A B 13 14
43 |
44 | A XERR 50A O 15 14COLOR(RED)
45 | A R HEADER_FMT
46 | A OVERLAY
47 | A 3 06'F12=Back Enter=Create'
48 | A COLOR(BLU)
49 | A 2 33'New Employee'
50 | A DSPATR(UL)
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qddssrc/nemp.dspf:
--------------------------------------------------------------------------------
1 | A INDARA
2 | A CA12(12)
3 | A R DETAIL
4 | A 6 10'ID'
5 | A DSPATR(HI)
6 | A DSPATR(UL)
7 | A XID 6A O 6 14
8 |
9 | A 7 7'First'
10 | A DSPATR(UL)
11 | A COLOR(WHT)
12 | A XFIRST 12A B 7 14
13 |
14 | A 8 5'Initial'
15 | A DSPATR(UL)
16 | A COLOR(WHT)
17 | A XINIT 1A B 8 14
18 |
19 | A 9 8'Last'
20 | A DSPATR(UL)
21 | A COLOR(WHT)
22 | A XLAST 15A B 9 14
23 |
24 | A 10 2'Department'
25 | A DSPATR(UL)
26 | A COLOR(WHT)
27 | A XDEPT 3A O 10 14
28 |
29 | A 11 9'Job'
30 | A DSPATR(UL)
31 | A COLOR(WHT)
32 | A XJOB 8A B 11 14
33 |
34 | A 12 6'Salary'
35 | A DSPATR(UL)
36 | A COLOR(WHT)
37 | A XSAL 10A B 12 14
38 |
39 | A 13 7'Phone'
40 | A DSPATR(UL)
41 | A COLOR(WHT)
42 | A XTEL 4A B 13 14
43 |
44 | A XERR 50A O 15 14COLOR(RED)
45 | A R HEADER_FMT
46 | A OVERLAY
47 | A 3 06'F12=Back Enter=Create'
48 | A COLOR(BLU)
49 | A 2 33'New Employee'
50 | A DSPATR(UL)
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Source Orbit
4 |
5 |
6 |
7 | Source Orbit is a dependency management tool. As IBM i developers start using Git for their RPGLE, CL, DDS and SQL, we want to provide them with excellent tools to help them understand their source code. Source orbit is available for use as both a VS Code extension and CLI tool.
8 |
9 | * 💻 [Install from VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit)
10 | * 📦 [Download from Open VSX Registry](https://open-vsx.org/extension/IBM/vscode-sourceorbit)
11 | * ⚡[Install CLI from NPM](https://www.npmjs.com/package/@ibm/sourceorbit)
12 | * 📖 [View Documentation](https://ibm.github.io/sourceorbit/#/)
13 | * 🔎 [See Releases](https://github.com/IBM/sourceorbit/releases)
14 |
15 | [](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit)
16 | [](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit)
17 |
18 | [](https://www.npmjs.com/package/@ibm/sourceorbit)
19 | [](https://www.npmjs.com/package/@ibm/sourceorbit)
20 |
21 | ## Features
22 |
23 | Source Orbit is equipped to help you with the following tasks:
24 |
25 | 1. Scans all applicable source code to build a dependency tree
26 | 2. Show how objects would be affected as developers write code
27 | 3. Generate JSON, or build scripts, to automatically build your application changes
28 | 4. Generates reports for branches being worked on so project owners can see their application in real time
29 | 5. Migrate your code to git
30 |
31 | ## Getting Started
32 |
33 | Check out these pages to dive in:
34 |
35 | 1. [As a CLI](./pages/cli/index.md): Run Source Orbit as part of an automated pipeline, or anywhere really!
36 | 2. [As a VS Code Extension](./pages/extension/index.md): Leverage Source Orbit as you develop applications in VS Code
37 | 3. [Project Structure](./pages/developing/local/structure): Learn how to structure your code when stored in git
38 | 4. [Source Code Rules](./pages/general/rules.md): Learn what rules to abide by when using Source Orbit
--------------------------------------------------------------------------------
/cli/test/fixtures/include_mismatch_fix/QDDSSRC/ARTICLE.PF:
--------------------------------------------------------------------------------
1 | *%METADATA *
2 | * %TEXT Article File *
3 | *%EMETADATA *
4 | REF(SAMREF)
5 | R FARTI
6 | ARID R
7 | ARDESC R
8 | ARSALEPR R REFFLD(UNITPRICE)
9 | TEXT('REF SALE PRICE')
10 | COLHDG('REF' 'SALE' 'PRICE')
11 | EDTCDE(2)
12 | ARWHSPR R REFFLD(UNITPRICE)
13 | TEXT('STOCK PRICE')
14 | COLHDG('STOCK' 'PRICE')
15 | EDTCDE(2)
16 | ARTIFA R REFFLD(FAID)
17 | ARSTOCK R REFFLD(QUANTITY)
18 | TEXT('STOCK')
19 | COLHDG('STOCK')
20 | EDTCDE(2)
21 | ARMINQTY R REFFLD(QUANTITY)
22 | TEXT('MINIMUM STOCK')
23 | COLHDG('MINIMUM' 'STOCK')
24 | EDTCDE(2)
25 | ARCUSQTY R REFFLD(QUANTITY)
26 | TEXT('CUSTOMER ORDER QUANTITY')
27 | COLHDG('CUSTOMER' 'ORDER' 'QTY')
28 | ARPURQTY R REFFLD(QUANTITY)
29 | TEXT('PURCHASE ORDER QUANTITY')
30 | COLHDG('PRUCHASE' 'ORDER' 'QTY')
31 | EDTCDE(2)
32 | ARVATCD R REFFLD(VATCODE)
33 | ARCREA L TEXT('CREATION DATE')
34 | COLHDG('CREAETION' 'DATE')
35 | ARMOD Z TEXT('LAST MODIFICATION')
36 | COLHDG('LAST' 'MODIFICATION')
37 | ARMODID 10 TEXT('LAS MOD BY')
38 | COLHDG('LAST' 'MODIF.' 'BY')
39 | ARDEL R REFFLD(DLCODE)
40 |
--------------------------------------------------------------------------------
/vs/README.md:
--------------------------------------------------------------------------------
1 | # Source Orbit
2 |
3 |
4 |
5 | Source Orbit is a dependency management tool. As IBM i developers start using Git for their RPGLE, CL, DDS and SQL, we want to provide them with excellent tools to help them understand their source code. Source orbit is available for use as both a VS Code extension and CLI tool.
6 |
7 | * 💻 [Install from VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit)
8 | * 📦 [Download from Open VSX Registry](https://open-vsx.org/extension/IBM/vscode-sourceorbit)
9 | * ⚡[Install CLI from NPM](https://www.npmjs.com/package/@ibm/sourceorbit)
10 | * 📖 [View Documentation](https://ibm.github.io/sourceorbit/#/)
11 | * 🔎 [See Releases](https://github.com/IBM/sourceorbit/releases)
12 |
13 | [](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit)
14 | [](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit)
15 |
16 | [](https://www.npmjs.com/package/@ibm/sourceorbit)
17 | [](https://www.npmjs.com/package/@ibm/sourceorbit)
18 |
19 | ## Features
20 |
21 | Source Orbit is equipped to help you with the following tasks:
22 |
23 | 1. Scans all applicable source code to build a dependency tree
24 | 2. Show how objects would be affected as developers write code
25 | 3. Generate JSON, or build scripts, to automatically build your application changes
26 | 4. Generates reports for branches being worked on so project owners can see their application in real time
27 | 5. Migrate your code to git
28 |
29 | ## Getting Started
30 |
31 | Check out these pages to dive in:
32 |
33 | 1. [As a CLI](https://ibm.github.io/sourceorbit/#/./pages/cli/index): Run Source Orbit as part of an automated pipeline, or anywhere really!
34 | 2. [As a VS Code Extension](https://ibm.github.io/sourceorbit/#/./pages/extension/index): Leverage Source Orbit as you develop applications in VS Code
35 | 3. [Project Structure](https://ibm.github.io/sourceorbit/#/./pages/general/structure): Learn how to structure your code when stored in git
36 | 4. [Source Code Rules](https://ibm.github.io/sourceorbit/#/./pages/general/rules): Learn what rules to abide by when using Source Orbit
--------------------------------------------------------------------------------
/cli/test/fixtures/mixedCaseExport/qrpglesrc/modexcept.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 | //%METADATA *
3 | // %TEXT module for exceptions. *
4 | //%EMETADATA *
5 | ctl-opt nomain ;
6 |
7 | dcl-pr getRandomMethodA char(10);
8 | inProdCode char(10) const;
9 | inState char(2) const;
10 | inEffectiveDate date const;
11 | inSignedDate date const;
12 | inReceivedDate date const;
13 | inIssuedDate date const;
14 | inExceptionID char(10) const;
15 | inExceptionCode char(10) const;
16 | END-PR;
17 | //*************************************************************************************************
18 | dcl-proc getRandomMethodA export;
19 | dcl-pi getRandomMethodA char(10);
20 | inProdCode char(10) const;
21 | inState char(2) const;
22 | inEffectiveDate date const;
23 | inSignedDate date const;
24 | inReceivedDate date const;
25 | inIssuedDate date const;
26 | inExceptionID char(10) const;
27 | inExceptionCode char(10) const;
28 | END-PI;
29 | dcl-s rtAction char(10);
30 |
31 | if sqlstt = '00000';
32 | return rtAction;
33 | else;
34 | return '';
35 | ENDIF;
36 | END-PROC;
37 |
38 | dcl-proc BigFootLivesInSc export;
39 | dcl-pi BigFootLivesInSc ind;
40 | inProdCode char(10) const;
41 | inState char(2) const;
42 | inEffectiveDate date const;
43 | inStrategy char(10) const;
44 | END-PI;
45 | dcl-s authCode char(10);
46 |
47 | authCode = getRandomMethodA(inProdCode:inState:inEffectiveDate:
48 | inEffectiveDate:inEffectiveDate:inEffectiveDate:'STRATEGY':inStrategy);
49 |
50 | if authCode = '' or authCode = 'ALLOW';
51 | return *on;
52 | else;
53 | return *off;
54 | ENDIF;
55 | END-PROC;
56 |
57 | dcl-proc validateCoolness export;
58 | dcl-pi validateCoolness ind;
59 | inPolYear packed(3:0) const;
60 | inPolMon packed(2:0) const;
61 | inPolSeq packed(6:0) const;
62 | inProdCode char(10) const;
63 | inStateCode char(2) const;
64 | inTheDate date const;
65 | END-PI;
66 | dcl-s strategyID char(10);
67 | dcl-s rtError ind inz(*on);
68 |
69 | ENDIF;
70 | exec sql fetch next from allocCheck into :strategyID;
71 | dow sqlstt = '00000';
72 | if not BigFootLivesInSc(inProdCode:inStateCode:inTheDate:strategyID);
73 | rtError = *off;
74 | ENDIF;
75 | ENDDO;
76 |
77 | return rtError;
78 |
79 | END-PROC;
80 |
81 |
--------------------------------------------------------------------------------
/cli/test/fixtures/from_qsys/qsqlsrc/empmst.sql:
--------------------------------------------------------------------------------
1 | -- Employee Master
2 | -- Generated on: 11/03/21 14:32:20
3 | CREATE OR REPLACE TABLE EMPMST (
4 | -- SQL150B 10 REUSEDLT(*NO) in table EMPMST in PAYROLL1 ignored.
5 | ACREC CHAR(1) CCSID 37 NOT NULL DEFAULT '' ,
6 | EMPNO DECIMAL(6, 0) NOT NULL DEFAULT 0 ,
7 | ENAME CHAR(30) CCSID 37 NOT NULL DEFAULT '' ,
8 | EMCAT CHAR(1) CCSID 37 NOT NULL DEFAULT '' ,
9 | EDEPT CHAR(5) CCSID 37 NOT NULL DEFAULT '' ,
10 | ELOCN CHAR(30) CCSID 37 NOT NULL DEFAULT '' ,
11 | EUSRI CHAR(8) CCSID 37 NOT NULL DEFAULT '' ,
12 | ENHRS DECIMAL(3, 1) NOT NULL DEFAULT 0 ,
13 | EPHRC DECIMAL(5, 1) NOT NULL DEFAULT 0 ,
14 | EPHRY DECIMAL(7, 1) NOT NULL DEFAULT 0 ,
15 | EPHRP DECIMAL(7, 1) NOT NULL DEFAULT 0 ,
16 | EPNRC DECIMAL(5, 1) NOT NULL DEFAULT 0 ,
17 | EPNRY DECIMAL(7, 1) NOT NULL DEFAULT 0 ,
18 | EPNRP DECIMAL(7, 1) NOT NULL DEFAULT 0 ,
19 | PRIMARY KEY( EMPNO ) )
20 |
21 | RCDFMT RCEMP ;
22 |
23 | LABEL ON COLUMN EMPMST
24 | ( EMPNO IS 'EMPLOYEE NUMBER' ,
25 | ENAME IS 'EMPLOYEE NAME' ,
26 | EMCAT IS 'EMP CAT' ,
27 | EDEPT IS 'EMPL DEPT' ,
28 | ELOCN IS 'EMPLOYEE LOCATION' ,
29 | EUSRI IS 'EMPLOYEE USRID' ,
30 | ENHRS IS 'NORMAL WK HRS' ,
31 | EPHRC IS 'PRJ HRS CUR MTH' ,
32 | EPHRY IS 'PRJ HRS YTD' ,
33 | EPHRP IS 'PRJ HRS PRIOR YR' ,
34 | EPNRC IS 'NON PRJ HRS CUR MTH' ,
35 | EPNRY IS 'NON PRJ HRS YTD' ,
36 | EPNRP IS 'NON PRJ HRS PRIOR YR' ) ;
37 |
38 | LABEL ON COLUMN EMPMST
39 | ( ACREC TEXT IS 'ACTIVE RECORD CODE' ,
40 | EMPNO TEXT IS 'EMPLOYEE NUMBER' ,
41 | ENAME TEXT IS 'EMPLOYEE NAME' ,
42 | EMCAT TEXT IS 'EMPLOYEE CATEGORY' ,
43 | EDEPT TEXT IS 'EMPLOYEE DEPARTMENT' ,
44 | ELOCN TEXT IS 'EMPLOYEE LOCATION' ,
45 | EUSRI TEXT IS 'EMPLOYEE USRID' ,
46 | ENHRS TEXT IS 'EMPLOYEE NORMAL WEEK HOURS' ,
47 | EPHRC TEXT IS 'PROJECT HOURS CURRENT MONTH' ,
48 | EPHRY TEXT IS 'PROJECT HOURS YEAR TO DATE' ,
49 | EPHRP TEXT IS 'PROJECT HOURS PRIOR YEAR' ,
50 | EPNRC TEXT IS 'NON PROJECT HOURS CURR MONTH' ,
51 | EPNRY TEXT IS 'NON PROJECT HOURS YTD' ,
52 | EPNRP TEXT IS 'NON PROJECT HOURS PRIOR YEAR' ) ;
53 |
54 | GRANT DELETE , INSERT , SELECT , UPDATE
55 | ON EMPMST TO PUBLIC ;
56 |
57 | -- GRANT ALTER , DELETE , INDEX , INSERT , REFERENCES , SELECT , UPDATE
58 | -- ON EMPMST TO USRPRF(*OWNER) WITH GRANT OPTION ;
59 |
60 |
--------------------------------------------------------------------------------
/cli/readme.md:
--------------------------------------------------------------------------------
1 | # Source Orbit
2 |
3 |
4 |
5 | Source Orbit is a dependency management tool. As IBM i developers start using Git for their RPGLE, CL, DDS and SQL, we want to provide them with excellent tools to help them understand their source code. Source orbit is available for use as both a VS Code extension and CLI tool.
6 |
7 | * 💻 [Install from VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit)
8 | * 📦 [Download from Open VSX Registry](https://open-vsx.org/extension/IBM/vscode-sourceorbit)
9 | * ⚡[Install CLI from NPM](https://www.npmjs.com/package/@ibm/sourceorbit)
10 | * 📖 [View Documentation](https://ibm.github.io/sourceorbit/#/)
11 | * 🔎 [See Releases](https://github.com/IBM/sourceorbit/releases)
12 |
13 | [](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit)
14 | [](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit)
15 |
16 | [](https://www.npmjs.com/package/@ibm/sourceorbit)
17 | [](https://www.npmjs.com/package/@ibm/sourceorbit)
18 |
19 | ## General Usage
20 |
21 | Source Orbit will scan the sources in the current working directory (CWD) and can do a few things:
22 |
23 | * Show object dependencies with `-l`
24 | * Generate a different file formats based on the dependency tree to build the project
25 | * Rename files easily (`.rpgle`/`.clle`/`.clp` -> `.pgm.rpgle`/`.pgm.clle`/`.clle`) with `-ar`
26 | * Fix RPGLE includes if the source is found locally (useful for converting from member include style) with `-fi`
27 | * List detailed information with `--verbose`
28 | * Want to only scan a specific source? Use the `-s` option: `so -s qrpglesrc/employees.pgm.sqlrpgle`
29 |
30 | ```sh
31 | cd myibmiproject
32 | so -h
33 | so -bf make && gmake BIN_LIB=libname
34 | ```
35 |
36 | ## Getting Started
37 |
38 | Check out these pages to dive in:
39 |
40 | 1. [As a CLI](https://ibm.github.io/sourceorbit/#/./pages/cli/index): Run Source Orbit as part of an automated pipeline, or anywhere really!
41 | 2. [As a VS Code Extension](https://ibm.github.io/sourceorbit/#/./pages/extension/index): Leverage Source Orbit as you develop applications in VS Code
42 | 3. [Project Structure](https://ibm.github.io/sourceorbit/#/./pages/general/structure): Learn how to structure your code when stored in git
43 | 4. [Source Code Rules](https://ibm.github.io/sourceorbit/#/./pages/general/rules): Learn what rules to abide by when using Source Orbit
--------------------------------------------------------------------------------
/cli/src/builders/actions/index.ts:
--------------------------------------------------------------------------------
1 | import { ReadFileSystem } from "../../readFileSystem";
2 | import { Targets } from "../../targets";
3 | import path from "path";
4 |
5 | export interface Action {
6 | name: string,
7 | command: string,
8 | environment: "ile",
9 | extensions: string[],
10 | }
11 |
12 | export class ProjectActions {
13 | private actions: { [relativePath: string]: Action[] } = {};
14 |
15 | constructor(private readonly targets: Targets, private readonly readFileSystem: ReadFileSystem) {}
16 |
17 | get getActionPaths() {
18 | return Object.keys(this.actions);
19 | }
20 |
21 | public async loadAllActions() {
22 | const cwd = this.targets.getCwd();
23 | const files = await this.readFileSystem.getFiles(cwd, `**/actions.json`, {dot: true});
24 |
25 | for (const file of files) {
26 | const relativePath = path.relative(cwd, file);
27 | const contents = await this.readFileSystem.readFile(file);
28 | try {
29 | const possibleActions = JSON.parse(contents) as Partial;
30 |
31 | for (const possibleAction of possibleActions) {
32 | if (!possibleAction.name || !possibleAction.command || !possibleAction.environment || !possibleAction.extensions) {
33 | // TODO: Log a warning about missing required fields
34 | continue; // Skip if required fields are missing
35 | }
36 |
37 | possibleAction.extensions = possibleAction.extensions.map(ext => ext.toLowerCase());
38 | }
39 |
40 | this.actions[relativePath] = possibleActions as Action[];
41 | } catch (e) {
42 | console.log(`Error parsing actions.json at ${relativePath}:`, e);
43 | }
44 | }
45 |
46 | const vscodePath = path.join(`.vscode`, `actions.json`);
47 | if (this.actions[vscodePath]) {
48 | // If there is a .vscode/actions.json, it is the project actions
49 | this.actions[`actions.json`] = this.actions[vscodePath];
50 | delete this.actions[vscodePath];
51 | }
52 | }
53 |
54 | getActionForPath(relativeSourcePath: string): Action|undefined {
55 | let allPossibleActions: Action[] = [];
56 | let parent: string = relativeSourcePath;
57 |
58 | while (true) {
59 | parent = path.dirname(parent);
60 |
61 | const actionFile = path.join(parent, `actions.json`);
62 |
63 | if (this.actions[actionFile]) {
64 | allPossibleActions.push(...this.actions[actionFile]);
65 | }
66 |
67 | if (parent === `.`) {
68 | // Reached the root directory, stop searching
69 | break;
70 | }
71 | }
72 |
73 | let extension = path.extname(relativeSourcePath).toLowerCase();
74 |
75 | if (extension.startsWith(`.`)) {
76 | extension = extension.slice(1);
77 | }
78 |
79 | allPossibleActions = allPossibleActions.filter((action) => {
80 | return action.extensions.includes(extension);
81 | });
82 |
83 | return allPossibleActions[0];
84 | }
85 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_with_bnddir/qtestsrc/empdett.test.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt nomain BNDDIR('APP');
4 |
5 | /include 'qrpgleref/empdet.rpgleinc'
6 | /include qinclude,TESTCASE
7 |
8 | exec sql
9 | set option commit = *none;
10 |
11 | dcl-proc setUpSuite export;
12 | // Insert sample data into employee
13 | exec sql
14 | insert into employee (
15 | empno, firstnme, midinit, lastname, workdept, phoneno,
16 | hiredate, job, edlevel, sex, birthdate, salary, bonus, comm
17 | ) values
18 | ('000010', 'CHRISTINE', 'I', 'HAAS', 'A00', '3978', '01/01/65', 'PRES', 18, 'F', null, 52750, 1000, 4220),
19 | ('000020', 'MICHAEL', 'L', 'THOMPSON', 'B01', '3476', '10/10/73', 'MANAGER', 18, 'M', '02/02/48', 41250, 800, 3300),
20 | ('200120', 'GREG', '', 'ORLANDO', 'A00', '2167', '05/05/72', 'CLERK', 14, 'M', '10/18/42', 29250, 600, 2340);
21 |
22 | if (sqlcode <> 0 and sqlcode <> -803);
23 | fail('Failed to insert into employee table with SQL code: ' + %char(sqlcode));
24 | endif;
25 |
26 | // Insert sample data in department table
27 | exec sql
28 | insert into department (
29 | deptno, deptname, mgrno, admrdept, location
30 | ) values
31 | ('A00', 'SPIFFY COMPUTER SERVICE DIV.', '000010', 'A00', 'NEW YORK'),
32 | ('B01', 'PLANNING', '000020', 'A00', 'ATLANTA');
33 |
34 | if (sqlcode <> 0 and sqlcode <> -803);
35 | fail('Failed to insert into department table with SQL code: ' + %char(sqlcode));
36 | endif;
37 | end-proc;
38 |
39 | dcl-proc test_getEmployeeDetail_found export;
40 | dcl-pi *n extproc(*dclcase) end-pi;
41 |
42 | dcl-s empno char(6);
43 | dcl-ds actual likeDS(employee_detail_t);
44 | dcl-ds expected likeDS(employee_detail_t);
45 |
46 | // Input
47 | empno = '000010';
48 |
49 | // Actual results
50 | actual = getEmployeeDetail(empno);
51 |
52 | // Expected results
53 | expected.found = *on;
54 | expected.name = 'CHRISTINE I HAAS';
55 | expected.netincome = 57970;
56 |
57 | // Assertions
58 | nEqual(expected.found : actual.found : 'found');
59 | aEqual(expected.name : actual.name : 'name');
60 | assert(expected.netincome = actual.netincome : 'netincome' );
61 | end-proc;
62 |
63 | dcl-proc test_getDeptDetail_found export;
64 | dcl-pi *n extproc(*dclcase) end-pi;
65 |
66 | dcl-s deptno char(3);
67 | dcl-ds actual likeDS(department_detail_t);
68 | dcl-ds expected likeDS(department_detail_t);
69 |
70 | // Input
71 | deptno = 'A00';
72 |
73 | // Actual results
74 | actual = getDeptDetail(deptno);
75 |
76 | // Expected results
77 | expected.found = *on;
78 | expected.deptname = 'SPIFFY COMPUTER SERVICE DIV.';
79 | expected.location = 'NEW YORK';
80 | expected.totalsalaries = 90160;
81 |
82 | // Assertions
83 | nEqual(expected.found : actual.found : 'found');
84 | aEqual(expected.deptname : actual.deptname : 'deptname');
85 | aEqual(expected.location : actual.location : 'location');
86 | assert(expected.totalsalaries = actual.totalsalaries : 'totalsalaries');
87 | end-proc;
--------------------------------------------------------------------------------
/cli/test/multiModule2.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, expect, test } from 'vitest';
2 |
3 | import { Targets } from '../src/targets'
4 | import { MakeProject } from '../src/builders/make';
5 | import { setupFixture } from './fixtures/projects';
6 | import { ReadFileSystem } from '../src/readFileSystem';
7 |
8 |
9 | describe(`multi_module_two tests`, () => {
10 | const project = setupFixture(`multi_module_two`);
11 | const fs = new ReadFileSystem();
12 | const targets = new Targets(project.cwd, fs);
13 |
14 | beforeAll(async () => {
15 | project.setup();
16 |
17 | await targets.loadProject();
18 |
19 | expect(targets.getTargets().length).toBeGreaterThan(0);
20 | targets.resolveBinder();
21 | });
22 |
23 | test(`Check objects are generated`, async () => {
24 | expect(targets.getResolvedObjects().length).toBe(5);
25 | expect(targets.getTargets().length).toBe(5);
26 | expect(targets.getTargetsOfType(`FILE`).length).toBe(1);
27 | expect(targets.getTargetsOfType(`PGM`).length).toBe(1);
28 | expect(targets.getTargetsOfType(`MODULE`).length).toBe(3);
29 | expect(targets.getTargetsOfType(`SRVPGM`).length).toBe(0);
30 | });
31 |
32 | test(`Check program`, async () => {
33 | const runnerPgm = targets.getTarget({systemName: `RUNNER`, type: `PGM`});
34 | expect(runnerPgm).toBeDefined();
35 |
36 | const deps = runnerPgm.deps;
37 | expect(deps.length).toBe(3);
38 |
39 | expect(deps.some(d => d.systemName === `DB`)).toBeTruthy();
40 | expect(deps.some(d => d.systemName === `RUNNER`)).toBeTruthy();
41 | expect(deps.some(d => d.systemName === `DATA`)).toBeTruthy();
42 | });
43 |
44 | test(`Check data module`, async () => {
45 | const dataModule = targets.getTarget({systemName: `DB`, type: `MODULE`});
46 | expect(dataModule).toBeDefined();
47 |
48 | const deps = dataModule.deps;
49 | expect(deps.length).toBe(2);
50 |
51 | expect(deps.some(d => d.systemName === `CUSTOMER`)).toBeTruthy();
52 | expect(deps.some(d => d.systemName === `DATA`)).toBeTruthy();
53 | });
54 |
55 | test(`Check makefile result`, async () => {
56 | const makeProject = new MakeProject(project.cwd, targets, fs);
57 | await makeProject.setupSettings();
58 |
59 | const targetContent = makeProject.getMakefile();
60 |
61 | const runnerTarget = targetContent.find(t => t.startsWith(`$(PREPATH)/RUNNER.PGM: `) && t.length > 50);
62 | expect(runnerTarget).toBeDefined();
63 | const runnerDepsString = runnerTarget.substring(runnerTarget.indexOf(`: `) + 2).split(` `);
64 | expect(runnerDepsString.length).toBe(3);
65 | expect(runnerDepsString).toContain(`$(PREPATH)/DB.MODULE`);
66 | expect(runnerDepsString).toContain(`$(PREPATH)/RUNNER.MODULE`);
67 | expect(runnerDepsString).toContain(`$(PREPATH)/DATA.MODULE`);
68 |
69 | expect(targetContent).toContain(`\tsystem "CRTPGM PGM($(BIN_LIB)/RUNNER) ENTMOD(RUNNER) MODULE(DB RUNNER DATA) TGTRLS(*CURRENT) BNDDIR($(APP_BNDDIR)) ACTGRP(*NEW)" > .logs/runner.splf`);
70 | expect(targetContent).toContain(`$(PREPATH)/RUNNER.MODULE: rpgle/runner.pgm.rpgle`);
71 | });
72 | });
--------------------------------------------------------------------------------
/docs/pages/extension/index.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | [Source Orbit](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-sourceorbit) is available as a Visual Studio Code extension. It offers the ability to use the same CLI features but with a UI that makes it much more convenient to use and visualize!
4 |
5 | ## View Impacted Objects
6 |
7 | The extension comes built with two views for viewing the impacted objects in your project.
8 |
9 | The `Source Impacts` view in the `Explorer` view container will render the impacted objects for the current active editor.
10 |
11 |
12 |
13 |
14 |
15 | The `Change Impacts` view in the `Source Control` view container will render the impacted objects for any files changed detected by Git.
16 |
17 |
18 |
19 |
20 |
21 | ## IBM i Project Explorer Integration
22 |
23 | Source Orbit integrates seemlessly with the [IBM i Project Explorer](https://marketplace.visualstudio.com/items?itemName=IBM.vscode-ibmi-projectexplorer) extension to allow you to visualize an object dependency tree for your IBM i project. It also provides you easy access to following commonly used Source Orbit features:
24 |
25 | * **Auto Fix** (equivalent to [CLI cleanup capabilities](./pages/cli/index?id=cleanup-capabilities))
26 | * `File Names`: This fixes most extensions for your project. For example, adds the `.pgm` attribute where possible, changes RPGLE headers to use `.rpgleinc` and fixes SQL sources to use right extension based on the `CREATE` statement inside of it.
27 | * `RPGLE Includes`: This will scan all RPGLE source code in your project and change the include statements to use the unix style path if the mapped source member can be found in the current working directory.
28 | * **Generate Build File** (equivalent to [CLI dependency file generation](./pages/cli/index?id=dependency-file-generation))
29 | * `json`: Generate all dependency info as JSON (`sourceorbit.json` in the root of the project)
30 | * `bob`: Generate the required `Rules.mk` files for Bob
31 | * `make`: Generates a single makefile with the targets and rules
32 | * `imd`: Generate analysis reports for branches (`impact.md` in the root of the project)
33 |
34 | The source migration tool built into IBM i Project Explorer can also automatically perform these tasks after migrating your source from QSYS. Check out more details [here](./pages/general/migrating?id=_1-ibm-i-project-explorer).
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/cli/test/fixtures/include_mismatch_fix/QPROTOSRC/ARTICLE.RPGLE:
--------------------------------------------------------------------------------
1 | *%METADATA *
2 | * %TEXT Function Article *
3 | *%EMETADATA *
4 | *=============================================
5 | * Get ARTICLE DESCRPTION
6 | *=============================================
7 | DGetArtDesc PR 50A
8 | D ARID 6A value
9 | *=============================================
10 | * Get REF SALE PRICE
11 | *=============================================
12 | DGetArtRefSalPrice...
13 | D pr 7P 2
14 | D ARID 6A value
15 | *=============================================
16 | * Get STOCK PRICE
17 | *=============================================
18 | DGetArtStockPrice...
19 | D PR 7P 2
20 | D ARID 6A value
21 | *=============================================
22 | * Get FAMILLY ID
23 | *=============================================
24 | DGetArtFam PR 3A
25 | D ARID 6A value
26 | *=============================================
27 | * Get STOCK
28 | *=============================================
29 | DGetArtStock PR 5P 0
30 | D ARID 6A value
31 | *=============================================
32 | * Get MINIMUM STOCK
33 | *=============================================
34 | DGetArtMinStock PR 5P 0
35 | D ARID 6A value
36 | *=============================================
37 | * Get VAT code
38 | *=============================================
39 | DGetArtVatCode Pr 1A
40 | D P_ARID 6A value
41 | *=============================================
42 | * Check if article exist
43 | *=============================================
44 | D ExistArt PR n
45 | D ARID 6A value
46 | *=============================================
47 | * Get DELETE CODE X=DELETED
48 | *=============================================
49 | DIsArtDeleted PR n
50 | D ARID 6A value
51 | *=============================================
52 | * Select an article
53 | *=============================================
54 | D SltArticle PR 6
55 | D ARID 6A value
56 | *=============================================
57 | * Get ARTICLE Info
58 | *=============================================
59 | DGetArtInfo PR 1520A
60 | D ARID 6A value
61 | *=============================================
62 | * Close ARTICLE1
63 | *=============================================
64 | D CloseARTICLE1 PR
65 |
--------------------------------------------------------------------------------
/cli/src/targets/languages.ts:
--------------------------------------------------------------------------------
1 | import { FileOptions, ILEObject, ObjectType, Targets } from ".";
2 | import { clExtensions, clleTargetCallback, clObjects } from "./languages/clle";
3 | import { ddsExtension, ddsObjects, ddsTargetCallback } from "./languages/dds";
4 | import { rpgleExtensions, rpgleObjects, rpgleTargetCallback } from "./languages/rpgle";
5 | import { sqlExtensions, sqlObjects, sqlTargetCallback } from "./languages/sql";
6 | import { binderExtensions, binderObjects, binderTargetCallback } from "./languages/binder";
7 | import { cmdExtensions, cmdObjects, cmdTargetCallback } from "./languages/cmd";
8 | import { noSourceObjects, noSourceTargetCallback, noSourceTargetObjects } from "./languages/nosrc";
9 |
10 | export type LanguageCallback = (targets: Targets, relativePath: string, content: string, ileObject: ILEObject) => Promise
11 | interface LanguageGroup {
12 | extensions: string[];
13 | callback: LanguageCallback;
14 | }
15 |
16 | export type ExtensionMap = {[ext: string]: ObjectType};
17 |
18 | export class TargetsLanguageProvider {
19 | private languageTargets: LanguageGroup[] = [];
20 | private extensionMap: ExtensionMap = {};
21 |
22 | constructor() {
23 | this.registerLanguage(clExtensions, clleTargetCallback, clObjects);
24 | this.registerLanguage(sqlExtensions, sqlTargetCallback, sqlObjects);
25 | this.registerLanguage(ddsExtension, ddsTargetCallback, ddsObjects);
26 | this.registerLanguage(binderExtensions, binderTargetCallback, binderObjects);
27 | this.registerLanguage(cmdExtensions, cmdTargetCallback, cmdObjects);
28 | this.registerLanguage(noSourceObjects, noSourceTargetCallback, noSourceTargetObjects);
29 | this.registerLanguage(rpgleExtensions, rpgleTargetCallback, rpgleObjects);
30 | }
31 |
32 | public getExtensions() {
33 | return this.languageTargets.map(lang => lang.extensions).flat();
34 | }
35 |
36 | public getGlob(additionalExtensions: string[] = []): string {
37 | const allExtensions = this.getExtensions().concat(additionalExtensions);
38 | return `**/*.{${allExtensions.join(`,`)},${allExtensions.map(e => e.toUpperCase()).join(`,`)}}`;
39 | }
40 |
41 | public async handleLanguage(targets: Targets, relativePath: string, content: string, ileObject: ILEObject) {
42 | const ext = relativePath.split('.').pop()?.toLowerCase();
43 | const language = this.languageTargets.find(lang => lang.extensions.includes(ext));
44 | if (ext && language) {
45 | await language.callback(targets, relativePath, content, ileObject);
46 | }
47 | }
48 |
49 | public registerLanguage(extensions: string[], callback: LanguageCallback, objectTypes: ExtensionMap = {}) {
50 | for (const ext of extensions) {
51 | if (this.languageTargets.some(lang => lang.extensions.includes(ext))) {
52 | throw new Error(`Language with extension '${ext}' is already registered.`);
53 | }
54 | }
55 |
56 | this.extensionMap = {...this.extensionMap, ...objectTypes};
57 |
58 | this.languageTargets.push({extensions, callback});
59 | }
60 |
61 | public getObjectType(ext: string): ObjectType | undefined {
62 | return this.extensionMap[ext.toLowerCase()];
63 | }
64 |
65 | public getObjectMap(): ExtensionMap {
66 | return this.extensionMap;
67 | }
68 |
69 | public getObjectTypes(): ObjectType[] {
70 | return Object.values(this.extensionMap);
71 | }
72 | }
--------------------------------------------------------------------------------
/cli/test/fixtures/cs_srvpgm/qtestsrc/emptest.test.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 |
3 | ctl-opt nomain bnddir('APP');
4 |
5 | /include 'qrpgleref/empdet.rpgleinc'
6 | /include qinclude,TESTCASE
7 |
8 | dcl-proc setUpSuite export;
9 | // Insert sample data into employee
10 | exec sql
11 | insert into employee (
12 | empno, firstnme, midinit, lastname, workdept, phoneno,
13 | hiredate, job, edlevel, sex, birthdate, salary, bonus, comm
14 | ) values
15 | ('000010', 'CHRISTINE', 'I', 'HAAS', 'A00', '3978', '01/01/65', 'PRES', 18, 'F', null, 52750, 1000, 4220),
16 | ('000020', 'MICHAEL', 'L', 'THOMPSON', 'B01', '3476', '10/10/73', 'MANAGER', 18, 'M', '02/02/48', 41250, 800, 3300),
17 | ('200120', 'GREG', '', 'ORLANDO', 'A00', '2167', '05/05/72', 'CLERK', 14, 'M', '10/18/42', 29250, 600, 2340);
18 |
19 | if (sqlcode <> 0 and sqlcode <> -803);
20 | fail('Failed to insert into employee table');
21 | endif;
22 |
23 | // Insert sample data in department table
24 | exec sql
25 | insert into department (
26 | deptno, deptname, mgrno, admrdept, location
27 | ) values
28 | ('A00', 'SPIFFY COMPUTER SERVICE DIV.', '000010', 'A00', 'NEW YORK'),
29 | ('B01', 'PLANNING', '000020', 'A00', 'ATLANTA');
30 |
31 | if (sqlcode <> 0 and sqlcode <> -803);
32 | fail('Failed to insert into department table');
33 | endif;
34 | end-proc;
35 |
36 | dcl-proc tearDownSuite export;
37 | // Delete sample data from employee
38 | exec sql
39 | delete from employee
40 | where empno in ('000010', '000020', '200120');
41 |
42 | if (sqlcode <> 0);
43 | fail('Failed to delete from employee table');
44 | return;
45 | endif;
46 |
47 | // Delete sample data from department
48 | exec sql
49 | delete from department
50 | where deptno in ('A00', 'B01');
51 |
52 | if (sqlcode <> 0);
53 | fail('Failed to delete from department table');
54 | return;
55 | endif;
56 | end-proc;
57 |
58 | dcl-proc test_getEmployeeDetail_found export;
59 | dcl-pi *n extproc(*dclcase) end-pi;
60 |
61 | dcl-s empno char(6);
62 | dcl-ds actual likeDS(employee_detail_t);
63 | dcl-ds expected likeDS(employee_detail_t);
64 |
65 | // Input
66 | empno = '000010';
67 |
68 | // Actual results
69 | actual = getEmployeeDetail(empno);
70 |
71 | // Expected results
72 | expected.found = *on;
73 | expected.name = 'CHRISTINE I HAAS';
74 | expected.netincome = 57970;
75 |
76 | // Assertions
77 | nEqual(expected.found : actual.found : 'found');
78 | aEqual(expected.name : actual.name : 'name');
79 | assert(expected.netincome = actual.netincome : 'netincome' );
80 | end-proc;
81 |
82 | dcl-proc test_getDeptDetail_found export;
83 | dcl-pi *n extproc(*dclcase) end-pi;
84 |
85 | dcl-s deptno char(3);
86 | dcl-ds actual likeDS(department_detail_t);
87 | dcl-ds expected likeDS(department_detail_t);
88 |
89 | // Input
90 | deptno = 'A00';
91 |
92 | // Actual results
93 | actual = getDeptDetail(deptno);
94 |
95 | // Expected results
96 | expected.found = *on;
97 | expected.deptname = 'SPIFFY COMPUTER SERVICE DIV.';
98 | expected.location = 'NEW YORK';
99 | expected.totalsalaries = 90160;
100 |
101 | // Assertions
102 | nEqual(expected.found : actual.found : 'found');
103 | aEqual(expected.deptname : actual.deptname : 'deptname');
104 | aEqual(expected.location : actual.location : 'location');
105 | assert(expected.totalsalaries = actual.totalsalaries : 'totalsalaries');
106 | end-proc;
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system/qrpglesrc/employees.pgm.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 | Ctl-Opt DFTACTGRP(*no);
3 |
4 | Dcl-Pi EMPLOYEES;
5 | DEPTNO Char(3);
6 | End-Pi;
7 |
8 | //---------------------------------------------------------------*
9 |
10 | /include 'qrpgleref/constants.rpgleinc'
11 |
12 | //---------------------------------------------------------------*
13 |
14 | Dcl-F emps WORKSTN Sfile(SFLDta:Rrn) IndDS(WkStnInd) InfDS(fileinfo);
15 |
16 | Dcl-S Exit Ind Inz(*Off);
17 |
18 | Dcl-S Rrn Zoned(4:0) Inz;
19 |
20 | Dcl-DS WkStnInd;
21 | ProcessSCF Ind Pos(21);
22 | ReprintScf Ind Pos(22);
23 | Error Ind Pos(25);
24 | PageDown Ind Pos(30);
25 | PageUp Ind Pos(31);
26 | SflEnd Ind Pos(40);
27 | SflBegin Ind Pos(41);
28 | NoRecord Ind Pos(60);
29 | SflDspCtl Ind Pos(85);
30 | SflClr Ind Pos(75);
31 | SflDsp Ind Pos(95);
32 | End-DS;
33 |
34 | Dcl-DS FILEINFO;
35 | FUNKEY Char(1) Pos(369);
36 | End-DS;
37 |
38 | //---------------------------------------------------------------*
39 | //
40 | Dcl-S Index Int(5);
41 |
42 | Dcl-Ds Employee ExtName('EMPLOYEE') Alias Qualified;
43 | End-Ds;
44 |
45 | //------------------------------------------------------------reb04
46 | Exit = *Off;
47 | LoadSubfile();
48 |
49 | Dow (Not Exit);
50 | Write FOOTER_FMT;
51 | Exfmt SFLCTL;
52 |
53 | Select;
54 | When (Funkey = F12);
55 | Exit = *On;
56 | When (Funkey = ENTER);
57 | HandleInputs();
58 |
59 | Endsl;
60 | Enddo;
61 |
62 | *INLR = *ON;
63 | Return;
64 |
65 | //------------------------------------------------------------
66 |
67 | Dcl-Proc ClearSubfile;
68 | SflDspCtl = *Off;
69 | SflDsp = *Off;
70 |
71 | Write SFLCTL;
72 |
73 | SflDspCtl = *On;
74 |
75 | rrn = 0;
76 | End-Proc;
77 |
78 | Dcl-Proc LoadSubfile;
79 | Dcl-S lCount Int(5);
80 | Dcl-S Action Char(1);
81 | Dcl-S LongAct Char(3);
82 |
83 | ClearSubfile();
84 |
85 | EXEC SQL DECLARE empCur CURSOR FOR
86 | SELECT EMPNO, FIRSTNME, LASTNAME, JOB
87 | FROM EMPLOYEE
88 | WHERE WORKDEPT = :DEPTNO;
89 |
90 | EXEC SQL OPEN empCur;
91 |
92 | if (sqlstate = '00000');
93 |
94 | dou (sqlstate <> '00000');
95 | EXEC SQL
96 | FETCH NEXT FROM empCur
97 | INTO :Employee.EMPNO,
98 | :Employee.FIRSTNME,
99 | :Employee.LASTNAME,
100 | :Employee.JOB;
101 |
102 | if (sqlstate = '00000');
103 | XID = Employee.EMPNO;
104 | XNAME = %TrimR(Employee.LASTNAME) + ', '
105 | + %TrimR(Employee.FIRSTNME);
106 | XJOB = Employee.JOB;
107 |
108 | rrn += 1;
109 | Write SFLDTA;
110 | endif;
111 | enddo;
112 |
113 | endif;
114 |
115 | EXEC SQL CLOSE empCur;
116 |
117 | If (rrn > 0);
118 | SflDsp = *On;
119 | SFLRRN = 1;
120 | Endif;
121 | End-Proc;
122 |
123 | Dcl-Proc HandleInputs;
124 | Dcl-S SelVal Char(1);
125 |
126 | Dou (%EOF(emps));
127 | ReadC SFLDTA;
128 | If (%EOF(emps));
129 | Iter;
130 | Endif;
131 |
132 | SelVal = %Trim(XSEL);
133 |
134 | Select;
135 | When (SelVal = '5');
136 | DSPLY XID;
137 | Endsl;
138 |
139 | If (XSEL <> *Blank);
140 | XSEL = *Blank;
141 | Update SFLDTA;
142 | SFLRRN = rrn;
143 | Endif;
144 | Enddo;
145 | End-Proc;
146 |
--------------------------------------------------------------------------------
/cli/test/fixtures/company_system_no_pgm_ext/qrpglesrc/employees.sqlrpgle:
--------------------------------------------------------------------------------
1 | **free
2 | Ctl-Opt DFTACTGRP(*no);
3 |
4 | Dcl-Pi EMPLOYEES;
5 | DEPTNO Char(3);
6 | End-Pi;
7 |
8 | //---------------------------------------------------------------*
9 |
10 | /include 'qrpgleref/constants.rpgleinc'
11 |
12 | //---------------------------------------------------------------*
13 |
14 | Dcl-F emps WORKSTN Sfile(SFLDta:Rrn) IndDS(WkStnInd) InfDS(fileinfo);
15 |
16 | Dcl-S Exit Ind Inz(*Off);
17 |
18 | Dcl-S Rrn Zoned(4:0) Inz;
19 |
20 | Dcl-DS WkStnInd;
21 | ProcessSCF Ind Pos(21);
22 | ReprintScf Ind Pos(22);
23 | Error Ind Pos(25);
24 | PageDown Ind Pos(30);
25 | PageUp Ind Pos(31);
26 | SflEnd Ind Pos(40);
27 | SflBegin Ind Pos(41);
28 | NoRecord Ind Pos(60);
29 | SflDspCtl Ind Pos(85);
30 | SflClr Ind Pos(75);
31 | SflDsp Ind Pos(95);
32 | End-DS;
33 |
34 | Dcl-DS FILEINFO;
35 | FUNKEY Char(1) Pos(369);
36 | End-DS;
37 |
38 | //---------------------------------------------------------------*
39 | //
40 | Dcl-S Index Int(5);
41 |
42 | Dcl-Ds Employee ExtName('EMPLOYEE') Alias Qualified;
43 | End-Ds;
44 |
45 | //------------------------------------------------------------reb04
46 | Exit = *Off;
47 | LoadSubfile();
48 |
49 | Dow (Not Exit);
50 | Write FOOTER_FMT;
51 | Exfmt SFLCTL;
52 |
53 | Select;
54 | When (Funkey = F12);
55 | Exit = *On;
56 | When (Funkey = ENTER);
57 | HandleInputs();
58 |
59 | Endsl;
60 | Enddo;
61 |
62 | *INLR = *ON;
63 | Return;
64 |
65 | //------------------------------------------------------------
66 |
67 | Dcl-Proc ClearSubfile;
68 | SflDspCtl = *Off;
69 | SflDsp = *Off;
70 |
71 | Write SFLCTL;
72 |
73 | SflDspCtl = *On;
74 |
75 | rrn = 0;
76 | End-Proc;
77 |
78 | Dcl-Proc LoadSubfile;
79 | Dcl-S lCount Int(5);
80 | Dcl-S Action Char(1);
81 | Dcl-S LongAct Char(3);
82 |
83 | ClearSubfile();
84 |
85 | EXEC SQL DECLARE empCur CURSOR FOR
86 | SELECT EMPNO, FIRSTNME, LASTNAME, JOB
87 | FROM EMPLOYEE
88 | WHERE WORKDEPT = :DEPTNO;
89 |
90 | EXEC SQL OPEN empCur;
91 |
92 | if (sqlstate = '00000');
93 |
94 | dou (sqlstate <> '00000');
95 | EXEC SQL
96 | FETCH NEXT FROM empCur
97 | INTO :Employee.EMPNO,
98 | :Employee.FIRSTNME,
99 | :Employee.LASTNAME,
100 | :Employee.JOB;
101 |
102 | if (sqlstate = '00000');
103 | XID = Employee.EMPNO;
104 | XNAME = %TrimR(Employee.LASTNAME) + ', '
105 | + %TrimR(Employee.FIRSTNME);
106 | XJOB = Employee.JOB;
107 |
108 | rrn += 1;
109 | Write SFLDTA;
110 | endif;
111 | enddo;
112 |
113 | endif;
114 |
115 | EXEC SQL CLOSE empCur;
116 |
117 | If (rrn > 0);
118 | SflDsp = *On;
119 | SFLRRN = 1;
120 | Endif;
121 | End-Proc;
122 |
123 | Dcl-Proc HandleInputs;
124 | Dcl-S SelVal Char(1);
125 |
126 | Dou (%EOF(emps));
127 | ReadC SFLDTA;
128 | If (%EOF(emps));
129 | Iter;
130 | Endif;
131 |
132 | SelVal = %Trim(XSEL);
133 |
134 | Select;
135 | When (SelVal = '5');
136 | DSPLY XID;
137 | Endsl;
138 |
139 | If (XSEL <> *Blank);
140 | XSEL = *Blank;
141 | Update SFLDTA;
142 | SFLRRN = rrn;
143 | Endif;
144 | Enddo;
145 | End-Proc;
146 |
--------------------------------------------------------------------------------