Skip to content

Commit

Permalink
Improvement to support for DDS references
Browse files Browse the repository at this point in the history
Signed-off-by: worksofliam <[email protected]>
  • Loading branch information
worksofliam committed Feb 15, 2024
1 parent 07be34e commit 5f63161
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 58 deletions.
111 changes: 53 additions & 58 deletions cli/src/targets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,6 @@ export class Targets {
* Handles all DDS types: pf, lf, dspf
*/
private createDdsFileTarget(localPath: string, dds: dds, options: FileOptions = {}) {
const sourceName = path.basename(localPath);
const ileObject = this.resolvePathToObject(localPath, options.text);
const target: ILEObjectTarget = {
...ileObject,
Expand All @@ -492,47 +491,72 @@ export class Targets {

infoOut(`${ileObject.systemName}.${ileObject.type}: ${ileObject.relativePath}`);

// We have a local cache of refs found so we don't keep doing global lookups
// on objects we already know to depend on in this object.

let alreadyFoundRefs: string[] = [];

const handleObjectPath = (currentKeyword: string, recordFormat: any, value: string) => {
const qualified = value.split(`/`);

let objectName: string | undefined;
if (qualified.length === 2 && qualified[0].toLowerCase() === `*libl`) {
objectName = qualified[1];
} else if (qualified.length === 1) {
objectName = qualified[0];
}

if (objectName) {
const upperName = objectName.toUpperCase();
if (alreadyFoundRefs.includes(upperName)) return;

const resolvedPath = this.searchForObject({ systemName: upperName, type: `FILE` });
if (resolvedPath) {
target.deps.push(resolvedPath);
alreadyFoundRefs.push(upperName);
}
else {
this.logger.fileLog(ileObject.relativePath, {
message: `no object found for reference '${objectName}'`,
type: `warning`,
line: recordFormat.range.start
});
}
} else {
this.logger.fileLog(ileObject.relativePath, {
message: `${currentKeyword} reference not included as possible reference to library found.`,
type: `info`,
line: recordFormat.range.start
});
}
}

// PFILE -> https://www.ibm.com/docs/en/i/7.5?topic=80-pfile-physical-file-keywordlogical-files-only
// REF -> https://www.ibm.com/docs/en/i/7.5?topic=80-ref-reference-keywordphysical-files-only

const ddsRefKeywords = [`PFILE`, `REF`, `JFILE`];

for (const recordFormat of dds.formats) {

// Look through this record format keywords for the keyword we're looking for
for (const keyword of ddsRefKeywords) {
// Look through this record format keywords for the keyword we're looking for
const keywordObj = recordFormat.keywords.find(k => k.name === keyword);
if (keywordObj) {
const wholeValue: string = keywordObj.value;
const parts = wholeValue.split(` `).filter(x => x.length > 0);
for (const value of parts) {
const qualified = value.split(`/`);

let objectName: string | undefined;
if (qualified.length === 2 && qualified[0].toLowerCase() === `*libl`) {
objectName = qualified[1];
} else if (qualified.length === 1) {
objectName = qualified[0];
}

if (objectName) {
const resolvedPath = this.searchForObject({ systemName: objectName.toUpperCase(), type: `FILE` });
if (resolvedPath) target.deps.push(resolvedPath);
else {
this.logger.fileLog(ileObject.relativePath, {
message: `no object found for reference '${objectName}'`,
type: `warning`,
line: recordFormat.range.start
});
}
} else {
this.logger.fileLog(ileObject.relativePath, {
message: `${keyword} reference not included as possible reference to library found.`,
type: `info`,
line: recordFormat.range.start
});
}
// JFILE can have multiple files referenced in it, whereas
// REF and PFILE can only have one at the first element
const pathsToCheck = (keyword === `JFILE` ? parts.length : 1);

for (let i = 0; i < pathsToCheck; i++) {
handleObjectPath(keyword, recordFormat, parts[i]);
}
}
}

// REFFLD -> https://www.ibm.com/docs/en/i/7.5?topic=80-reffld-referenced-field-keywordphysical-files-only

// Then, let's loop through the fields in this format and see if we can find REFFLD
for (const field of recordFormat.fields) {
const refFld = field.keywords.find(k => k.name === `REFFLD`);
Expand All @@ -541,36 +565,7 @@ export class Targets {
const [fieldRef, fileRef] = refFld.value.trim().split(` `);

if (fileRef) {
const qualified = fileRef.split(`/`);

let objectName: string | undefined;
if (qualified.length === 2 && qualified[0].toLowerCase() === `*libl`) {
objectName = qualified[1];
} else if (qualified.length === 1) {
objectName = qualified[0];
}

if (objectName) {
const resolvedPath = this.searchForObject({ systemName: objectName.toUpperCase(), type: `FILE` });
if (resolvedPath) {
if (!target.deps.some(d => d.systemName === resolvedPath.systemName && d.type === resolvedPath.type)) {
target.deps.push(resolvedPath);
}
}
else {
this.logger.fileLog(ileObject.relativePath, {
message: `no object found for reference '${objectName}'`,
type: `warning`,
line: recordFormat.range.start
});
}
} else {
this.logger.fileLog(ileObject.relativePath, {
message: `REFFLD reference not included as possible reference to library found.`,
type: `info`,
line: recordFormat.range.start
});
}
handleObjectPath(`REFFLD`, recordFormat, fileRef);
}
}
}
Expand Down
86 changes: 86 additions & 0 deletions cli/test/ddsReferences.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { assert, beforeAll, describe, expect, test } from 'vitest';

import { Targets } from '../src/targets'
import path from 'path';
import { MakeProject } from '../src/builders/make';
import { getFiles } from '../src/utils';
import { setupFixture } from './fixtures/projects';
import { scanGlob } from '../src/extensions';
import { writeFileSync } from 'fs';

const cwd = setupFixture(`dds_refs`);

// This issue was occuring when you had two files with the same name, but different extensions.

let files = getFiles(cwd, scanGlob);

describe.skipIf(files.length === 0)(`dds_refs tests`, () => {
const targets = new Targets(cwd);
targets.setSuggestions({renames: true, includes: true})

beforeAll(async () => {
targets.loadObjectsFromPaths(files);
const parsePromises = files.map(f => targets.parseFile(f));
await Promise.all(parsePromises);

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

test(`Ensure objects are defined`, async () => {
expect(targets.getTargets().length).toBe(3);
expect(targets.getResolvedObjects(`FILE`).length).toBe(3);
expect(targets.binderRequired()).toBe(false);

const pro250d = targets.searchForObject({systemName: `PRO250D`, type: `FILE`});
expect(pro250d).toBeDefined();
const provider = targets.searchForObject({systemName: `PROVIDER`, type: `FILE`});
expect(provider).toBeDefined();
const provide1 = targets.searchForObject({systemName: `PROVIDE1`, type: `FILE`});
expect(provide1).toBeDefined();
});

test(`test PROD250D deps (REF & 32REFFLD)`, async () => {
const pro250d = targets.getTarget({systemName: `PRO250D`, type: `FILE`});

expect(pro250d).toBeDefined();
const deps = pro250d.deps;
expect(deps.length).toBe(1);
expect(deps[0].systemName).toBe(`PROVIDER`);

const logs = targets.logger.getLogsFor(pro250d.relativePath);
expect(logs.length).toBe(1);
expect(logs[0]).toMatchObject({
message: `no object found for reference 'COUNTRY'`,
type: `warning`,
line: 32
});
});

test(`test PROVIDER deps (REF)`, async () => {
const provider = targets.getTarget({systemName: `PROVIDER`, type: `FILE`});

expect(provider).toBeDefined();
const deps = provider.deps;
expect(deps.length).toBe(0);

const logs = targets.logger.getLogsFor(provider.relativePath);
expect(logs.length).toBe(1);
expect(logs[0]).toMatchObject({
message: `no object found for reference 'SAMREF'`,
type: `warning`,
line: -1
});
});

test(`test PROVIDE1 deps (REF)`, async () => {
const providerLf = targets.getTarget({systemName: `PROVIDE1`, type: `FILE`});

expect(providerLf).toBeDefined();
const deps = providerLf.deps;
expect(deps.length).toBe(1);

const logs = targets.logger.getLogsFor(providerLf.relativePath);
expect(logs).toBeUndefined();
});
});
67 changes: 67 additions & 0 deletions cli/test/fixtures/dds_refs/PRO250D.DSPF
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
*%METADATA *
* %TEXT Display Article *
*%EMETADATA *
A*%%TS SD 20210414 103200 VTAQUIN REL-V7R3M0 5770-WDS
A*%%EC
A DSPSIZ(24 80 *DS3)
A REF(*LIBL/PROVIDER FPROV)
A PRINT
A INDARA
A ERRSFL
A CA03(03)
A CA12(12)
A R FMT01
A*%%TS SD 20210330 110722 VTAQUIN REL-V7R3M0 5770-WDS
A CF04(04 'Prompt')
A 1 2'PRO250 '
A COLOR(BLU)
A 3 4'Type choices, press Enter.'
A COLOR(BLU)
A 23 3'F3=Exit'
A COLOR(BLU)
A 23 37'F12=Cancel'
A COLOR(BLU)
A 1 34'Provider by Id'
A DSPATR(HI)
A 5 4'Provider Id . . . . . .'
A 23 19'F4=Prompt'
A COLOR(BLU)
A PRID R B 5 29
A 40 ERRMSGID(ERR0103 *LIBL/SAMMSGF 40 &-
A ERRDATA)
A ERRDATA 6A P
A R FMT02
A*%%TS SD 20210414 103200 VTAQUIN REL-V7R3M0 5770-WDS
A CA07(07 'Items')
A 1 2'PRO250 '
A COLOR(BLU)
A 3 4'Press Enter to continue.'
A COLOR(BLU)
A 23 3'F3=Exit'
A COLOR(BLU)
A 23 37'F12=Cancel'
A COLOR(BLU)
A 5 4'Provider Id . . . . . :'
A 6 4'Name . . . . . . . . :'
A 7 4'Phone . . . . . . . . :'
A 8 4'Vat Nr . . . . . . . :'
A 9 4'eMail . . . . . . . . :'
A 10 4'Address . . . . . . . :'
A 13 4'Postal Code & City . :'
A 14 4'Country Code . . . . :'
A 1 34'Provider by Id'
A DSPATR(HI)
A PRID R O 5 29
A PROVNM R O 6 29
A PRPHONE R O 7 29
A PRVAT R O 8 29
A PRMAIL R O 9 29
A PRLINE1 R O 10 29
A PRLINE2 R O 11 29
A PRLINE3 R O 12 29
A PRZIP R O 13 29
A PRCOUN R O 14 29
A PRCITY R O 13 40
A COUNTR R O 14 32REFFLD(FCOUN/COUNTR *LIBL/COUNTRY)
A 23 18'F7=Items'
A COLOR(BLU)
6 changes: 6 additions & 0 deletions cli/test/fixtures/dds_refs/PROVIDE1.LF
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*%METADATA *
* %TEXT Provider file *
*%EMETADATA *
UNIQUE
R FPROV PFILE(PROVIDER)
K PRID
24 changes: 24 additions & 0 deletions cli/test/fixtures/dds_refs/PROVIDER.PF
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
*%METADATA *
* %TEXT Provider file *
*%EMETADATA *
REF(SAMREF)
R FPROV
PRID R
PROVNM R
PRCONT 30 TEXT('CONTACT PERSON')
PRPHONE R REFFLD(PHONE)
PRVAT R REFFLD(VATNUM)
PRMAIL R REFFLD(EMAIL)
PRLINE1 R REFFLD(ADRLINE)
PRLINE2 R REFFLD(ADRLINE)
PRLINE3 R REFFLD(ADRLINE)
PRZIP R REFFLD(ZIPCOD)
PRCITY R REFFLD(CITY)
PRCOUN R REFFLD(COID)
PRCREA L TEXT('CREATION DATE')
COLHDG('CREAETION' 'DATE')
PRMOD Z TEXT('LAST MODIFICATION')
COLHDG('LAST' 'MODIFICATION')
PRMODID 10 TEXT('LAS MOD BY')
COLHDG('LAST' 'MODIF.' 'BY')
PRDEL R REFFLD(DLCODE)

0 comments on commit 5f63161

Please sign in to comment.