From 918f9f5a37a44875e1bda98d9d2b7a09ac817c25 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 24 Jul 2025 08:43:09 -0400 Subject: [PATCH 1/4] Initial work to ignore unknown object types Signed-off-by: worksofliam --- cli/src/targets/index.ts | 36 ++++++++++++++--------------- cli/src/targets/languages.ts | 8 +++---- cli/src/targets/languages/binder.ts | 6 ++--- cli/src/targets/languages/clle.ts | 6 ++--- cli/src/targets/languages/cmd.ts | 6 ++--- cli/src/targets/languages/dds.ts | 6 ++--- cli/src/targets/languages/nosrc.ts | 6 ++--- cli/src/targets/languages/rpgle.ts | 10 ++++---- cli/src/targets/languages/sql.ts | 27 +++++++++++----------- 9 files changed, 51 insertions(+), 60 deletions(-) diff --git a/cli/src/targets/index.ts b/cli/src/targets/index.ts index 11ad318..8b5f634 100644 --- a/cli/src/targets/index.ts +++ b/cli/src/targets/index.ts @@ -153,7 +153,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 { if (this.resolvedObjects[localPath]) { if (newText) this.resolvedObjects[localPath].text = newText; return this.resolvedObjects[localPath]; @@ -168,6 +168,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, @@ -371,19 +380,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[]) { @@ -408,9 +406,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); @@ -422,11 +417,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.`, diff --git a/cli/src/targets/languages.ts b/cli/src/targets/languages.ts index 28b276a..a9871fc 100644 --- a/cli/src/targets/languages.ts +++ b/cli/src/targets/languages.ts @@ -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"; @@ -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 +export type LanguageCallback = (targets: Targets, relativePath: string, content: string, ileObject: ILEObject) => Promise interface LanguageGroup { extensions: string[]; callback: LanguageCallback; @@ -38,11 +38,11 @@ export class TargetsLanguageProvider { 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); } } diff --git a/cli/src/targets/languages/binder.ts b/cli/src/targets/languages/binder.ts index a8e38b9..1ed74ed 100644 --- a/cli/src/targets/languages/binder.ts +++ b/cli/src/targets/languages/binder.ts @@ -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"; @@ -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: [], diff --git a/cli/src/targets/languages/clle.ts b/cli/src/targets/languages/clle.ts index 10c0002..59aa260 100644 --- a/cli/src/targets/languages/clle.ts +++ b/cli/src/targets/languages/clle.ts @@ -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"; @@ -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, diff --git a/cli/src/targets/languages/cmd.ts b/cli/src/targets/languages/cmd.ts index afcf555..abe6c61 100644 --- a/cli/src/targets/languages/cmd.ts +++ b/cli/src/targets/languages/cmd.ts @@ -1,4 +1,4 @@ -import { FileOptions, Targets } from ".."; +import { FileOptions, ILEObject, Targets } from ".."; import { ExtensionMap } from "../languages"; export const cmdExtensions = [`cmd`]; @@ -6,6 +6,6 @@ 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! } \ No newline at end of file diff --git a/cli/src/targets/languages/dds.ts b/cli/src/targets/languages/dds.ts index 3601368..9a41bb1 100644 --- a/cli/src/targets/languages/dds.ts +++ b/cli/src/targets/languages/dds.ts @@ -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"; @@ -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: [] diff --git a/cli/src/targets/languages/nosrc.ts b/cli/src/targets/languages/nosrc.ts index 66536ba..674543a 100644 --- a/cli/src/targets/languages/nosrc.ts +++ b/cli/src/targets/languages/nosrc.ts @@ -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`]; @@ -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! } \ No newline at end of file diff --git a/cli/src/targets/languages/rpgle.ts b/cli/src/targets/languages/rpgle.ts index c186a04..6f46cee 100644 --- a/cli/src/targets/languages/rpgle.ts +++ b/cli/src/targets/languages/rpgle.ts @@ -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"; @@ -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( @@ -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`]) @@ -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 { diff --git a/cli/src/targets/languages/sql.ts b/cli/src/targets/languages/sql.ts index c205a87..8d49e59 100644 --- a/cli/src/targets/languages/sql.ts +++ b/cli/src/targets/languages/sql.ts @@ -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); @@ -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; @@ -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; } @@ -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 From bd30cbd2ca8f1fa1a1df28cb2fbda13094ea3870 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 24 Jul 2025 08:43:17 -0400 Subject: [PATCH 2/4] Fix test which sometimes will fail Signed-off-by: worksofliam --- cli/test/cs_with_bnddir.test.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cli/test/cs_with_bnddir.test.ts b/cli/test/cs_with_bnddir.test.ts index ece8517..57208e2 100644 --- a/cli/test/cs_with_bnddir.test.ts +++ b/cli/test/cs_with_bnddir.test.ts @@ -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`) From 8c1e19588a14fe87d30eb25b8425149efc14cd08 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 24 Jul 2025 08:48:16 -0400 Subject: [PATCH 3/4] Remove use of getSearchGlob and add new parameter to loadProjects Signed-off-by: worksofliam --- cli/src/index.ts | 2 +- cli/src/targets/index.ts | 12 ++++-------- cli/src/targets/languages.ts | 4 ++-- cli/test/ddsDepsWithRefFile.test.ts | 2 +- cli/test/overrideObjRef.test.ts | 6 +----- vs/server/src/TargetsManager.ts | 2 +- vs/server/src/setup.ts | 2 +- 7 files changed, 11 insertions(+), 19 deletions(-) diff --git a/cli/src/index.ts b/cli/src/index.ts index 3d10fca..d9a1ef7 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -177,7 +177,7 @@ async function main() { let files: string[]; if (!scanGlob) { - scanGlob = targets.getSearchGlob(); + scanGlob = Targets.LanguageProvider.getGlob(); } try { diff --git a/cli/src/targets/index.ts b/cli/src/targets/index.ts index 8b5f634..bfc1e48 100644 --- a/cli/src/targets/index.ts +++ b/cli/src/targets/index.ts @@ -95,10 +95,6 @@ export class Targets { return ignoredObjects; } - getSearchGlob(): string { - return Targets.LanguageProvider.getGlob(); - } - public getCwd() { return this.cwd; } @@ -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))); } diff --git a/cli/src/targets/languages.ts b/cli/src/targets/languages.ts index a9871fc..4b80dfe 100644 --- a/cli/src/targets/languages.ts +++ b/cli/src/targets/languages.ts @@ -33,8 +33,8 @@ 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(`,`)}}`; } diff --git a/cli/test/ddsDepsWithRefFile.test.ts b/cli/test/ddsDepsWithRefFile.test.ts index 33c41e3..2271802 100644 --- a/cli/test/ddsDepsWithRefFile.test.ts +++ b/cli/test/ddsDepsWithRefFile.test.ts @@ -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(); diff --git a/cli/test/overrideObjRef.test.ts b/cli/test/overrideObjRef.test.ts index 205203f..f1d18c5 100644 --- a/cli/test/overrideObjRef.test.ts +++ b/cli/test/overrideObjRef.test.ts @@ -1,13 +1,9 @@ -import { assert, beforeAll, describe, expect, test } from 'vitest'; +import { 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 { referencesFileName } from '../src/extensions'; -import { writeFileSync } from 'fs'; -import { BobProject } from '../src/builders/bob'; import { ReadFileSystem } from '../src/readFileSystem'; const cwd = setupFixture(`override_objref`); diff --git a/vs/server/src/TargetsManager.ts b/vs/server/src/TargetsManager.ts index e0ee567..95c7916 100644 --- a/vs/server/src/TargetsManager.ts +++ b/vs/server/src/TargetsManager.ts @@ -46,7 +46,7 @@ export class TargetsManager { const targets = new Targets(url, rfs); - const files = await rfs.getFiles(url, targets.getSearchGlob()); + const files = await rfs.getFiles(url, Targets.LanguageProvider.getGlob()); await targets.loadObjectsFromPaths(files); diff --git a/vs/server/src/setup.ts b/vs/server/src/setup.ts index 2810ff2..672a95c 100644 --- a/vs/server/src/setup.ts +++ b/vs/server/src/setup.ts @@ -93,7 +93,7 @@ export async function fixProject(workspaceUri: string, suggestions: TargetSugges const targets = new Targets(url, rfs); - const files = await rfs.getFiles(url, targets.getSearchGlob()); + const files = await rfs.getFiles(url, Targets.LanguageProvider.getGlob()); targets.setSuggestions(suggestions); From 2ac6f325043de35d2a7807aacd8bb53cbd1f13c3 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 24 Jul 2025 08:55:09 -0400 Subject: [PATCH 4/4] Test to prove rpgleinc files aren't objects Signed-off-by: worksofliam --- cli/test/cs_srvpgm.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cli/test/cs_srvpgm.test.ts b/cli/test/cs_srvpgm.test.ts index dbd4652..0f94020 100644 --- a/cli/test/cs_srvpgm.test.ts +++ b/cli/test/cs_srvpgm.test.ts @@ -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();