Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions cli/src/builders/bob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,18 @@ export class BobProject {
let list: DirectoryTargets = {};

for (let target of targets.getTargets()) {
let dirname: string|undefined;
if (target.relativePath) {
const dirname = path.dirname(target.relativePath);
dirname = path.dirname(target.relativePath);
} else if (target.type === `PGM`) {
// If there is no relative path, this might mean it's a multimodule program
const possibleModule = targets.getTarget({systemName: target.systemName, type: `MODULE`});
if (possibleModule) {
dirname = path.dirname(possibleModule.relativePath);
}
}

if (dirname) {
if (list[dirname] === undefined) list[dirname] = [];

list[dirname].push(target);
Expand Down Expand Up @@ -85,7 +95,7 @@ class RulesFile {

const existingLine = this.parsed.find(r => r.target === objName && r.isUserWritten !== true);

const lineContent = `${path.relative(this.subdir, target.relativePath)} ${target.headers ? target.headers.join(` `) + ` ` : ``}${target.deps.filter(d => d.reference !== true).map(d => `${d.systemName}.${d.type}`).join(` `)}`.trimEnd();
const lineContent = `${target.relativePath ? path.relative(this.subdir, target.relativePath) + ' ' : ``}${target.headers ? target.headers.join(` `) + ` ` : ``}${target.deps.filter(d => d.reference !== true).map(d => `${d.systemName}.${d.type}`).join(` `)}`.trimEnd();

if (existingLine) {
existingLine.ogLine = `${objName}: ${lineContent}`;
Expand Down
4 changes: 3 additions & 1 deletion cli/src/targets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ export class Targets {
const pathDetail = path.parse(localPath);
// define internal imports
ileObject.imports = cache.procedures
.filter((proc: any) => proc.keyword[`EXTPROC`])
.filter((proc: any) => proc.keyword[`EXTPROC`] && !proc.keyword[`EXPORT`])
.map(ref => {
const keyword = ref.keyword;
let importName: string = ref.name;
Expand Down Expand Up @@ -1507,6 +1507,7 @@ export class Targets {
systemName: currentTarget.systemName,
imports: currentTarget.imports,
exports: [],
headers: currentTarget.headers,
type: `MODULE`,
relativePath: basePath,
extension: path.extname(basePath).substring(1)
Expand All @@ -1521,6 +1522,7 @@ export class Targets {
// Clean up imports for module and program
newModTarget.imports = currentTarget.imports;
currentTarget.imports = undefined;
currentTarget.headers = undefined;

this.createOrAppend(currentTarget, newModule);
}
Expand Down
4 changes: 4 additions & 0 deletions cli/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export function getSystemNameFromPath(inputName: string) {
name = parts[1];
}

if (baseName.toUpperCase().endsWith(`.TEST`)) {
name = name.substring(0, name.length - 5);
}

// We start the system name with the suppliedPrefix
let systemName = prefix;

Expand Down
79 changes: 79 additions & 0 deletions cli/test/cs_srvpgm.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { beforeAll, describe, expect, test } from 'vitest';

import { Targets } from '../src/targets'
import { MakeProject } from '../src/builders/make';
import { setupFixture } from './fixtures/projects';
import { ReadFileSystem } from '../src/readFileSystem';
import { BobProject } from '../src/builders/bob';

describe(`pseudo tests`, () => {
const project = setupFixture(`cs_srvpgm`);

const fs = new ReadFileSystem();
const targets = new Targets(project.cwd, fs);
let make: MakeProject;

beforeAll(async () => {
project.setup();
await targets.loadProject();

expect(targets.getTargets().length).toBeGreaterThan(0);
targets.resolveBinder();

make = new MakeProject(project.cwd, targets);
});

test(`That test files are understood`, () => {
expect(targets).toBeDefined();

const testModule = targets.getTarget({systemName: `EMPTEST`, type: `MODULE`});
expect(testModule).toBeDefined();

expect(testModule.deps.length).toBe(3);
expect(testModule.deps.find(f => f.systemName === `EMPLOYEE`)).toBeDefined();
expect(testModule.deps.find(f => f.systemName === `DEPARTMENT`)).toBeDefined();
expect(testModule.deps.find(f => f.systemName === `EMPDET`)).toBeDefined();
});

test('Deps are picked up for the module', () => {
const empdet = targets.getTarget({systemName: `EMPDET`, type: `MODULE`});
expect(empdet).toBeDefined();

expect(empdet.deps.length).toBe(2);
expect(empdet.deps.find(f => f.systemName === `EMPLOYEE`)).toBeDefined();
expect(empdet.deps.find(f => f.systemName === `DEPARTMENT`)).toBeDefined();

const employees = targets.getTarget({systemName: `EMPLOYEES`, type: `PGM`});
expect(employees).toBeDefined();

expect(employees.deps.length).toBe(4);
expect(employees.deps.find(f => f.systemName === `EMPLOYEES` && f.type === `MODULE`)).toBeDefined();
expect(employees.deps.find(f => f.systemName === `EMPDET` && f.type === `MODULE`)).toBeDefined();
expect(employees.deps.find(f => f.systemName === `EMPS` && f.type === `FILE`)).toBeDefined();
expect(employees.deps.find(f => f.systemName === `EMPLOYEE` && f.type === `FILE`)).toBeDefined();
});

test('ibmi-bob rules', () => {
const bobProject = new BobProject(targets);

const files = bobProject.createRules();

expect(files[`Rules.mk`]).toBeDefined();
expect(files[`Rules.mk`]).toBe(`SUBDIRS = qddssrc qrpglesrc qtestsrc`);

expect(files[`qtestsrc/Rules.mk`]).toBe(`EMPTEST.MODULE: emptest.test.sqlrpgle qrpgleref/empdet.rpgleinc EMPLOYEE.FILE DEPARTMENT.FILE EMPDET.MODULE`)

Check failure on line 64 in cli/test/cs_srvpgm.test.ts

View workflow job for this annotation

GitHub Actions / build (windows-latest, 18.x)

test/cs_srvpgm.test.ts > pseudo tests > ibmi-bob rules

AssertionError: expected undefined to be 'EMPTEST.MODULE: emptest.test.sqlrpgle…' // Object.is equality - Expected: "EMPTEST.MODULE: emptest.test.sqlrpgle qrpgleref/empdet.rpgleinc EMPLOYEE.FILE DEPARTMENT.FILE EMPDET.MODULE" + Received: undefined ❯ test/cs_srvpgm.test.ts:64:40
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does it mean for a MODULE to be dependent on a different MODULE


console.log(files[`qrpglesrc/Rules.mk`]);
expect(files[`qrpglesrc/Rules.mk`]).toContain(`EMPLOYEES.MODULE: employees.pgm.sqlrpgle qrpgleref/constants.rpgleinc qrpgleref/empdet.rpgleinc`);
expect(files[`qrpglesrc/Rules.mk`]).toContain(`EMPLOYEES.PGM: EMPLOYEE.FILE EMPS.FILE EMPDET.MODULE EMPLOYEES.MODULE`);
});

test('makefile', () => {
const makefile = new MakeProject(targets.getCwd(), targets);

const contents = makefile.getMakefile().join(`\n`);

expect(contents).toContain(`$(PREPATH)/EMPLOYEES.PGM:`);
expect(contents).toContain(`system "CRTPGM PGM($(BIN_LIB)/EMPLOYEES) ENTMOD(EMPLOYEES) MODULE(EMPDET EMPLOYEES) TGTRLS(*CURRENT) BNDDIR($(BNDDIR)) ACTGRP(*NEW)" > .logs/employees.splf`);
});
});
29 changes: 29 additions & 0 deletions cli/test/fixtures/cs_srvpgm/qddssrc/department.table
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--https://www.ibm.com/docs/en/i/7.3?topic=tables-department-table-department

CREATE OR REPLACE TABLE DEPARTMENT
(DEPTNO CHAR(3) NOT NULL,
DEPTNAME VARCHAR(36) NOT NULL,
MGRNO CHAR(6) NOT NULL,
ADMRDEPT CHAR(3) NOT NULL,
LOCATION CHAR(16) NOT NULL,
PRIMARY KEY (DEPTNO));

ALTER TABLE DEPARTMENT
ADD FOREIGN KEY ROD (ADMRDEPT)
REFERENCES DEPARTMENT
ON DELETE CASCADE;

-- Remove circular reference
--ALTER TABLE DEPARTMENT
-- ADD FOREIGN KEY RDE (MGRNO)
-- REFERENCES EMPLOYEE
-- ON DELETE SET NULL;

-- CREATE UNIQUE INDEX XDEPT1
-- ON DEPARTMENT (DEPTNO);

-- CREATE INDEX XDEPT2
-- ON DEPARTMENT (MGRNO);

-- CREATE INDEX XDEPT3
-- ON DEPARTMENT (ADMRDEPT);
36 changes: 36 additions & 0 deletions cli/test/fixtures/cs_srvpgm/qddssrc/depts.dspf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
A INDARA
A CA03(03)
A R SFLDTA SFL
A RRN 4Y 0H
A* DISPLAY DTA
A XSEL 1A B 7 8
A XID 3A O 7 12
A XNAME 38A O 7 16
A* COLOR HELLO
A R SFLCTL SFLCTL(SFLDTA)
A SFLPAG(0014)
A SFLSIZ(9999)
A OVERLAY
A 85 SFLDSPCTL
A 95 SFLDSP
A N85 SFLCLR
A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
A*
A 6 6'Opt'
A DSPATR(HI)
A DSPATR(UL)
A 6 12'ID'
A DSPATR(HI)
A DSPATR(UL)
A 6 16'Name'
A DSPATR(UL)
A COLOR(WHT)
A R FOOTER_FMT
A OVERLAY
A 3 6'F3=Exit'
A COLOR(BLU)
A 2 35'Departments'
A DSPATR(UL)
A COLOR(WHT)
A 4 6'5=View 8=New Employee'
A COLOR(BLU)
34 changes: 34 additions & 0 deletions cli/test/fixtures/cs_srvpgm/qddssrc/employee.table
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
-- https://www.ibm.com/docs/en/i/7.3?topic=tables-employee-table-employee

CREATE OR REPLACE TABLE EMPLOYEE
(EMPNO CHAR(6) NOT NULL,
FIRSTNME VARCHAR(12) NOT NULL,
MIDINIT CHAR(1) NOT NULL,
LASTNAME VARCHAR(15) NOT NULL,
WORKDEPT CHAR(3) ,
PHONENO CHAR(4) ,
HIREDATE DATE ,
JOB CHAR(8) ,
EDLEVEL SMALLINT NOT NULL,
SEX CHAR(1) ,
BIRTHDATE DATE ,
SALARY DECIMAL(9,2) ,
BONUS DECIMAL(9,2) ,
COMM DECIMAL(9,2) ,
PRIMARY KEY (EMPNO));

-- Remove circular reference
-- ALTER TABLE EMPLOYEE
-- ADD FOREIGN KEY RED (WORKDEPT)
-- REFERENCES DEPARTMENT
-- ON DELETE SET NULL;

ALTER TABLE EMPLOYEE
ADD CONSTRAINT NUMBER
CHECK (PHONENO >= '0000' AND PHONENO <= '9998');

-- CREATE UNIQUE INDEX XEMP1
-- ON EMPLOYEE (EMPNO);

-- CREATE INDEX XEMP2
-- ON EMPLOYEE (WORKDEPT);
41 changes: 41 additions & 0 deletions cli/test/fixtures/cs_srvpgm/qddssrc/emps.dspf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
A INDARA
A CA12(12)
A R SFLDTA SFL
A RRN 4Y 0H
A* DISPLAY DTA
A XSEL 1A B 7 8
A XID 6A O 7 12
A XNAME 30A O 7 20
A XJOB 8A O 7 52
A* COLOR HELLO
A R SFLCTL SFLCTL(SFLDTA)
A SFLPAG(0014)
A SFLSIZ(9999)
A OVERLAY
A 85 SFLDSPCTL
A 95 SFLDSP
A N85 SFLCLR
A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
A*
A 6 6'Opt'
A DSPATR(HI)
A DSPATR(UL)
A 6 12'ID'
A DSPATR(HI)
A DSPATR(UL)
A 6 20'Name'
A DSPATR(UL)
A COLOR(WHT)
A 6 52'Job'
A DSPATR(UL)
A COLOR(WHT)
A 5 52'Total'
A DSPATR(UL)
A COLOR(WHT)
A XTOT 9S 2O 5 61
A R FOOTER_FMT
A OVERLAY
A 3 06'F12=Back'
A COLOR(BLU)
A 2 35'Employees'
A DSPATR(UL)
50 changes: 50 additions & 0 deletions cli/test/fixtures/cs_srvpgm/qddssrc/nemp.dspf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
A INDARA
A CA12(12)
A R DETAIL
A 6 10'ID'
A DSPATR(HI)
A DSPATR(UL)
A XID 6A O 6 14

A 7 7'First'
A DSPATR(UL)
A COLOR(WHT)
A XFIRST 12A B 7 14

A 8 5'Initial'
A DSPATR(UL)
A COLOR(WHT)
A XINIT 1A B 8 14

A 9 8'Last'
A DSPATR(UL)
A COLOR(WHT)
A XLAST 15A B 9 14

A 10 2'Department'
A DSPATR(UL)
A COLOR(WHT)
A XDEPT 3A O 10 14

A 11 9'Job'
A DSPATR(UL)
A COLOR(WHT)
A XJOB 8A B 11 14

A 12 6'Salary'
A DSPATR(UL)
A COLOR(WHT)
A XSAL 10A B 12 14

A 13 7'Phone'
A DSPATR(UL)
A COLOR(WHT)
A XTEL 4A B 13 14

A XERR 50A O 15 14COLOR(RED)
A R HEADER_FMT
A OVERLAY
A 3 06'F12=Back Enter=Create'
A COLOR(BLU)
A 2 33'New Employee'
A DSPATR(UL)
40 changes: 40 additions & 0 deletions cli/test/fixtures/cs_srvpgm/qddssrc/popdept.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
-------------------------------------------------------------------------------
-- This procedure will create 5 records into the department table
-------------------------------------------------------------------------------

create or replace procedure popdept()
language sql
Result Sets 0
Modifies SQL Data
Specific popdept
begin
declare i int default 1;
declare deptno char(3);
declare deptname varchar(36);
declare mgrno char(6);
declare admrdept char(3);
declare loc char(16);

while i <= 5 do
-- Generate random data (you can adjust this as needed)
set deptno = right('000' || cast(rand()*1000 as int), 3);
set mgrno = right('00000' || cast(rand()*1000000 as int), 6);
set admrdept = right('000' || cast(rand()*1000 as int), 3);
set loc = 'Location ' || deptno;

-- Assign department names based on specified categories
case
when i = 1 then set deptname = 'Admin';
when i = 2 then set deptname = 'IT';
when i = 3 then set deptname = 'Finance';
when i = 4 then set deptname = 'Management';
when i = 5 then set deptname = 'HR';
end case;

-- Insert into department table
insert into department (deptno, deptname, mgrno, admrdept, location)
values (deptno, deptname, mgrno, admrdept, loc) with nc;

set i = i + 1;
end while;
end;
Loading
Loading