Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.
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
2 changes: 1 addition & 1 deletion cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ async function main() {
let files: string[];

if (!scanGlob) {
scanGlob = targets.getSearchGlob();
scanGlob = Targets.LanguageProvider.getGlob();
}

try {
Expand Down
48 changes: 21 additions & 27 deletions cli/src/targets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,6 @@ export class Targets {
return ignoredObjects;
}

getSearchGlob(): string {
return Targets.LanguageProvider.getGlob();
}

public getCwd() {
return this.cwd;
}
Expand Down Expand Up @@ -139,12 +135,12 @@ export class Targets {
this.resolvedObjects[localPath] = ileObject;
}

public async loadProject(withRef?: string) {
if (withRef) {
await this.handleRefsFile(path.join(this.cwd, withRef));
public async loadProject(options: { withRef?: string, additionalExtensions?: string[] } = {}) {
if (options.withRef) {
await this.handleRefsFile(path.join(this.cwd, options.withRef));
}

const initialFiles = await this.fs.getFiles(this.cwd, this.getSearchGlob());
const initialFiles = await this.fs.getFiles(this.cwd, Targets.LanguageProvider.getGlob(options.additionalExtensions));
await this.loadObjectsFromPaths(initialFiles);
await Promise.allSettled(initialFiles.map(f => this.parseFile(f)));
}
Expand All @@ -153,7 +149,7 @@ export class Targets {
return [`MODULE`, `PGM`].includes(Targets.LanguageProvider.getObjectType(ext));
}

public async resolvePathToObject(localPath: string, newText?: string) {
public async resolvePathToObject(localPath: string, newText?: string): Promise<ILEObject|undefined> {
if (this.resolvedObjects[localPath]) {
if (newText) this.resolvedObjects[localPath].text = newText;
return this.resolvedObjects[localPath];
Expand All @@ -168,6 +164,15 @@ export class Targets {
const name = getSystemNameFromPath(hasProgramAttribute ? detail.name.substring(0, detail.name.length - 4) : detail.name);
const type: ObjectType = (isProgram ? "PGM" : this.getObjectType(relativePath, extension));

if (!type) {
this.logger.fileLog(relativePath, {
type: `warning`,
message: `Unknown object type for ${relativePath} with extension ${extension}.`
});

return;
}

const theObject: ILEObject = {
systemName: name,
type: type,
Expand Down Expand Up @@ -371,19 +376,8 @@ export class Targets {
}

// TODO: move this to language provider
getObjectType(relativePath: string, ext: string): ObjectType {
const objType = Targets.LanguageProvider.getObjectType(ext);

if (!objType) {
this.logger.fileLog(relativePath, {
type: `warning`,
message: `'${ext}' not found a matching object type. Defaulting to '${ext}'`
});

return (ext.toUpperCase() as ObjectType);
}

return objType;
getObjectType(relativePath: string, ext: string): ObjectType|undefined {
return Targets.LanguageProvider.getObjectType(ext);
}

public loadObjectsFromPaths(paths: string[]) {
Expand All @@ -408,9 +402,6 @@ export class Targets {
try {
const content = await this.fs.readFile(filePath);

// Really only applied to rpg
const isFree = (content.length >= 6 ? content.substring(0, 6).toLowerCase() === `**free` : false);

let textMatch;
try {
[textMatch] = content.match(TextRegex);
Expand All @@ -422,11 +413,14 @@ export class Targets {
} catch (e) { }

const options: FileOptions = {
isFree,
text: textMatch
};

await Targets.LanguageProvider.handleLanguage(this, filePath, content, options);
const ileObject = await this.resolvePathToObject(filePath, options.text);
if (ileObject) {
await Targets.LanguageProvider.handleLanguage(this, filePath, content, ileObject);
}

} catch (e) {
this.logger.fileLog(relative, {
message: `Failed to parse file.`,
Expand Down
12 changes: 6 additions & 6 deletions cli/src/targets/languages.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FileOptions, ObjectType, Targets } from ".";
import { FileOptions, ILEObject, ObjectType, Targets } from ".";
import { clExtensions, clleTargetCallback, clObjects } from "./languages/clle";
import { ddsExtension, ddsObjects, ddsTargetCallback } from "./languages/dds";
import { rpgleExtensions, rpgleObjects, rpgleTargetCallback } from "./languages/rpgle";
Expand All @@ -7,7 +7,7 @@ import { binderExtensions, binderObjects, binderTargetCallback } from "./languag
import { cmdExtensions, cmdObjects, cmdTargetCallback } from "./languages/cmd";
import { noSourceObjects, noSourceTargetCallback, noSourceTargetObjects } from "./languages/nosrc";

export type LanguageCallback = (targets: Targets, relativePath: string, content: string, options: FileOptions) => Promise<void>
export type LanguageCallback = (targets: Targets, relativePath: string, content: string, ileObject: ILEObject) => Promise<void>
interface LanguageGroup {
extensions: string[];
callback: LanguageCallback;
Expand All @@ -33,16 +33,16 @@ export class TargetsLanguageProvider {
return this.languageTargets.map(lang => lang.extensions).flat();
}

public getGlob() {
const allExtensions = this.getExtensions();
public getGlob(additionalExtensions: string[] = []): string {
const allExtensions = this.getExtensions().concat(additionalExtensions);
return `**/*.{${allExtensions.join(`,`)},${allExtensions.map(e => e.toUpperCase()).join(`,`)}}`;
}

public async handleLanguage(targets: Targets, relativePath: string, content: string, options: FileOptions = {}) {
public async handleLanguage(targets: Targets, relativePath: string, content: string, ileObject: ILEObject) {
const ext = relativePath.split('.').pop()?.toLowerCase();
const language = this.languageTargets.find(lang => lang.extensions.includes(ext));
if (ext && language) {
await language.callback(targets, relativePath, content, options);
await language.callback(targets, relativePath, content, ileObject);
}
}

Expand Down
6 changes: 2 additions & 4 deletions cli/src/targets/languages/binder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from "path";
import { CLParser, DefinitionType, Module, File } from "vscode-clle/language";
import { FileOptions, ILEObjectTarget, Targets } from "..";
import { FileOptions, ILEObject, ILEObjectTarget, Targets } from "..";
import { infoOut } from "../../cli";
import { trimQuotes } from "../../utils";
import { ExtensionMap } from "../languages";
Expand All @@ -11,15 +11,13 @@ export const binderObjects: ExtensionMap = {
bnd: `SRVPGM`,
}

export async function binderTargetCallback(targets: Targets, localPath: string, content: string, options: FileOptions) {
export async function binderTargetCallback(targets: Targets, localPath: string, content: string, ileObject: ILEObject) {
const clDocs = new CLParser();
const tokens = clDocs.parseDocument(content);

const module = new Module();
module.parseStatements(tokens);

const ileObject = await targets.resolvePathToObject(localPath, options.text);

const target: ILEObjectTarget = {
...ileObject,
deps: [],
Expand Down
6 changes: 2 additions & 4 deletions cli/src/targets/languages/clle.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from "path";
import { CLParser, DefinitionType, Module, File } from "vscode-clle/language";
import { FileOptions, ILEObjectTarget, Targets } from "..";
import { FileOptions, ILEObject, ILEObjectTarget, Targets } from "..";
import { infoOut } from "../../cli";
import { ExtensionMap } from "../languages";

Expand All @@ -11,15 +11,13 @@ export const clObjects: ExtensionMap = {
clp: `PGM`
}

export async function clleTargetCallback(targets: Targets, filePath: string, content: string, options: FileOptions) {
export async function clleTargetCallback(targets: Targets, filePath: string, content: string, ileObject: ILEObject) {
const clDocs = new CLParser();
const tokens = clDocs.parseDocument(content);

const module = new Module();
module.parseStatements(tokens);

const ileObject = await targets.resolvePathToObject(filePath);

const pathDetail = path.parse(filePath);
const target: ILEObjectTarget = {
...ileObject,
Expand Down
6 changes: 3 additions & 3 deletions cli/src/targets/languages/cmd.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { FileOptions, Targets } from "..";
import { FileOptions, ILEObject, Targets } from "..";
import { ExtensionMap } from "../languages";

export const cmdExtensions = [`cmd`];
export const cmdObjects: ExtensionMap = {
cmd: `CMD`
}

export async function cmdTargetCallback(targets: Targets, localPath: string, content: string, options: FileOptions) {
targets.resolvePathToObject(localPath, options.text);
export async function cmdTargetCallback(targets: Targets, localPath: string, content: string, ileObject: ILEObject) {
// Do nothing!
}
6 changes: 2 additions & 4 deletions cli/src/targets/languages/dds.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from "path";
import { DisplayFile as dds } from "vscode-displayfile/src/dspf";
import { FileOptions, ILEObjectTarget, Targets } from "..";
import { FileOptions, ILEObject, ILEObjectTarget, Targets } from "..";
import { infoOut } from "../../cli";
import { ExtensionMap } from "../languages";

Expand All @@ -12,14 +12,12 @@ export const ddsObjects: ExtensionMap = {
prtf: `FILE`
}

export async function ddsTargetCallback(targets: Targets, filePath: string, content: string, options: FileOptions) {
export async function ddsTargetCallback(targets: Targets, filePath: string, content: string, ileObject: ILEObject) {
const eol = content.indexOf(`\r\n`) >= 0 ? `\r\n` : `\n`;

const ddsFile = new dds();
ddsFile.parse(content.split(eol));

const ileObject = await targets.resolvePathToObject(filePath, options.text);

const target: ILEObjectTarget = {
...ileObject,
deps: []
Expand Down
6 changes: 3 additions & 3 deletions cli/src/targets/languages/nosrc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Targets, FileOptions } from "..";
import { Targets, FileOptions, ILEObject } from "..";
import { ExtensionMap } from "../languages";

export const noSourceObjects = [`dtaara`, `mnucmd`, `msgf`, `dtaq`, `bnddir`];
Expand All @@ -10,6 +10,6 @@ export const noSourceTargetObjects: ExtensionMap = {
bnddir: `BNDDIR`
}

export async function noSourceTargetCallback(targets: Targets, localPath: string, content: string, options: FileOptions) {
targets.resolvePathToObject(localPath, options.text);
export async function noSourceTargetCallback(targets: Targets, localPath: string, content: string, ileObject: ILEObject) {
// Do nothing!
}
10 changes: 5 additions & 5 deletions cli/src/targets/languages/rpgle.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from "path";
import { FileOptions, ILEObjectTarget, Targets } from "..";
import { FileOptions, ILEObject, ILEObjectTarget, Targets } from "..";
import { infoOut } from "../../cli";
import Parser from "vscode-rpgle/language/parser";
import { IncludeStatement } from "vscode-rpgle/language/parserTypes";
Expand All @@ -20,7 +20,7 @@ interface RpgLookup {

const includeFileCache: { [path: string]: string } = {};

export async function rpgleTargetCallback(targets: Targets, localPath: string, content: string, options: FileOptions) {
export async function rpgleTargetCallback(targets: Targets, localPath: string, content: string, ileObject: ILEObject) {
const parser = setupParser(targets);

const cache = await parser.getDocs(
Expand All @@ -33,9 +33,9 @@ export async function rpgleTargetCallback(targets: Targets, localPath: string, c
);

if (cache) {
const ileObject = await targets.resolvePathToObject(localPath, options.text);

const isFree = (content.length >= 6 ? content.substring(0, 6).toLowerCase() === `**free` : false);
const pathDetail = path.parse(localPath);

// define internal imports
ileObject.imports = cache.procedures
.filter((proc: any) => proc.keyword[`EXTPROC`] && !proc.keyword[`EXPORT`])
Expand Down Expand Up @@ -125,7 +125,7 @@ export async function rpgleTargetCallback(targets: Targets, localPath: string, c
type: `includeFix`,
line: include.line,
change: {
lineContent: (options.isFree ? `` : ``.padEnd(6)) + `/copy '${theIncludePath}'`
lineContent: (isFree ? `` : ``.padEnd(6)) + `/copy '${theIncludePath}'`
}
});
} else {
Expand Down
27 changes: 13 additions & 14 deletions cli/src/targets/languages/sql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const sqlObjects: ExtensionMap = {
'sqltrg': `PGM`
}

export async function sqlTargetCallback(targets: Targets, localPath: string, content: string, options: FileOptions) {
export async function sqlTargetCallback(targets: Targets, localPath: string, content: string, ileObject: ILEObject) {
const document = new Document(content);

const pathDetail = path.parse(localPath);
Expand Down Expand Up @@ -130,16 +130,18 @@ export async function sqlTargetCallback(targets: Targets, localPath: string, con
let hasLongName = mainDef.object.name && mainDef.object.name.length > 10 ? mainDef.object.name : undefined;
let objectName = mainDef.object.system || trimQuotes(mainDef.object.name, `"`);

const extension = pathDetail.ext.substring(1);
// let ileObject: ILEObject = {
// systemName: objectName.toUpperCase(),
// longName: hasLongName,
// type: targets.getObjectType(relativePath, mainDef.createType),
// text: defaultObject.text,
// relativePath,
// extension
// }

let ileObject: ILEObject = {
systemName: objectName.toUpperCase(),
longName: hasLongName,
type: targets.getObjectType(relativePath, mainDef.createType),
text: options.text,
relativePath,
extension
}
ileObject.systemName = objectName.toUpperCase();
ileObject.longName = hasLongName;
ileObject.type = targets.getObjectType(relativePath, mainDef.createType);

let suggestRename = false;
const sqlFileName = pathDetail.name;
Expand All @@ -152,7 +154,7 @@ export async function sqlTargetCallback(targets: Targets, localPath: string, con
}

// Then make an extension suggestion
if (extension.toUpperCase() === `SQL` && mainDef.createType) {
if (ileObject.extension.toUpperCase() === `SQL` && mainDef.createType) {
suggestRename = true;
}

Expand Down Expand Up @@ -214,9 +216,6 @@ export async function sqlTargetCallback(targets: Targets, localPath: string, con
infoOut(`Depends on: ${newTarget.deps.map(d => `${d.systemName}.${d.type}`).join(` `)}`);
}

// So we can later resolve the path to the created object
targets.storeResolved(localPath, ileObject);

targets.addNewTarget(newTarget);

// If the extension is SQL, let's make better suggestions
Expand Down
7 changes: 5 additions & 2 deletions cli/test/cs_srvpgm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ describe(`pseudo tests`, () => {

beforeAll(async () => {
project.setup();
await targets.loadProject();
await targets.loadProject({additionalExtensions: [`rpgleinc`]});

expect(targets.getResolvedObjects().length).toBe(13);
expect(targets.getResolvedObjectsByFileExtension(`rpgleinc`).length).toBe(0);

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

make = new MakeProject(project.cwd, targets, fs);
await make.setupSettings();
Expand Down
9 changes: 8 additions & 1 deletion cli/test/cs_with_bnddir.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,14 @@ describe(`pseudo tests`, () => {
const files = bobProject.createRules();

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

const subdirs = files[`Rules.mk`].split(`SUBDIRS = `)[1].trim().split(` `);
expect(subdirs.length).toBe(4);
expect(subdirs).toContain(`qddssrc`);
expect(subdirs).toContain(`qrpglesrc`);
expect(subdirs).toContain(`qsqlsrc`);
expect(subdirs).toContain(`qtestsrc`);

expect(files[path.join(`qtestsrc`,`Rules.mk`)]).toBe(`TEMPDETT.MODULE: empdett.test.sqlrpgle qrpgleref/empdet.rpgleinc EMPLOYEE.FILE DEPARTMENT.FILE APP.BNDDIR`)

Expand Down
2 changes: 1 addition & 1 deletion cli/test/ddsDepsWithRefFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe(`dds_refs tests with reference file`, () => {
targets.setSuggestions({renames: true, includes: true})

beforeAll(async () => {
await targets.loadProject(`.objrefs`);
await targets.loadProject({withRef: `.objrefs`});

expect(targets.getTargets().length).toBeGreaterThan(0);
targets.resolveBinder();
Expand Down
Loading
Loading