undefined is not a function TypeError

Post Reply
dfsocha
Newbie
Posts: 15
Joined: Wed Aug 16, 2017 8:51 pm

undefined is not a function TypeError

Post by dfsocha »

Hello all! I'm getting an error when running my workflow that has a Node.JS script element in it. I'm running Switch Spring 2022. I'm working on these script updates because I need to update to a newer version of Switch but I have a TON of legacy scripts that need to be converted to Node.JS so I'm starting with a small/easy script and it's not going that great ;)

The error I'm getting is:
undefined is not a function TypeError: undefined is not a function at jobArrived (C:\Users\enfocusswitch\AppData\Roaming\Enfocus\SwitchProcessorService\cache\7ce230b50ef35d1b9adecf311dd1baa99d4fdea10c8394276d9b97258fa46f44\1731425389\main.js:1:3647) at _0xbe11ff (C:\Program Files\Enfocus\Enfocus Switch\ScriptExecutor\nodemodules\node_modules\switch-scripting\index.js:1231:34) at C:\Users\enfocusswitch\AppData\Roaming\Enfocus\SwitchProcessorService\cache\7ce230b50ef35d1b9adecf311dd1baa99d4fdea10c8394276d9b97258fa46f44\1731425389\main.js:1:5847 at AsyncResource.runInAsyncScope (node:async_hooks:201:9) at C:\Users\enfocusswitch\AppData\Roaming\Enfocus\SwitchProcessorService\cache\7ce230b50ef35d1b9adecf311dd1baa99d4fdea10c8394276d9b97258fa46f44\1731425389\main.js:1:5504 at new Promise (<anonymous>) at entrypointWrapper (C:\Users\enfocusswitch\AppData\Roaming\Enfocus\SwitchProcessorService\cache\7ce230b50ef35d1b9adecf311dd1baa99d4fdea10c8394276d9b97258fa46f44\1731425389\main.js:1:5321) at C:\Users\enfocusswitch\AppData\Roaming\Enfocus\SwitchProcessorService\cache\7ce230b50ef35d1b9adecf311dd1baa99d4fdea10c8394276d9b97258fa46f44\1731425389\main.js:1:7539 at _0x1a94d4.run (C:\Program Files\Enfocus\Enfocus Switch\ScriptExecutor\NodeScriptExecutor.js:429:30) at async process.<anonymous> (C:\Program Files\Enfocus\Enfocus Switch\ScriptExecutor\NodeScriptExecutor.js:280:41)

I used the Switch Scripter tool to create my directory structure, I then programmed everything in my main.ts file and configured other files as necessary. In my SSCRIPT, I linked to the main.ts file that I put my code into. The script is designed to read an XML file, see if a field has a _1 or something else and, depending on that field, is supposed to send the file down a specific path.

Here's the code for my main.ts file:

Code: Select all

/// <reference types="switch-scripting" />
import { readFile } from 'fs/promises';
import { XMLParser } from 'fast-xml-parser';

export async function jobArrived(flowElement: FlowElement, job: Job) {
    try {
        // Retrieve the dataset
        const dataset = await job.getDataset('Processed DSF JDF', AccessLevel.ReadOnly);
        if (!dataset) {
            await job.log(LogLevel.Warning, "Dataset 'Processed DSF JDF' not found");
            await job.sendToSingle("2");
            return;
        }

        // Access the dataset file path
        const datasetPath = await job.get(AccessLevel.ReadOnly);
        if (!datasetPath) {
            await job.log(LogLevel.Warning, 'Unable to access dataset file');
            await job.sendToSingle("2");
            return;
        }

        // Read and parse the dataset XML
        const xmlContent = await readFile(datasetPath, 'utf-8');
        const parser = new XMLParser({ ignoreAttributes: false });
        const xmlData = parser.parse(xmlContent);

        // Navigate the parsed XML to get the UserFileName attribute
        const jdf = xmlData['dn:JDF']?.['dn:JDF']?.['dn:ResourcePool']?.['dn:RunList']?.['dn:RunList']?.['dn:LayoutElement']?.['dn:FileSpec'];
        const unparsedJobNumber = jdf?.['@_UserFileName'];

        if (!unparsedJobNumber) {
            await job.log(LogLevel.Warning, 'Unable to retrieve job number from metadata');
            await job.sendToSingle("2");
            return;
        }

        const endPosition = unparsedJobNumber.toUpperCase().indexOf('.PDF');
        if (endPosition === -1) {
            await job.log(LogLevel.Warning, 'Job number format is incorrect');
            await job.sendToSingle("2");
            return;
        }

        const cleanedJobNumber = unparsedJobNumber.substring(0, endPosition);
        const parts = cleanedJobNumber.split('_');
        if (parts.length < 2) {
            await job.log(LogLevel.Warning, 'Job number format is incorrect');
            await job.sendToSingle("2");
            return;
        }

        const externalSubJobID = parts[1];

        // Send job to the appropriate output based on the sub-job ID
        if (externalSubJobID === '1') {
            await job.log(LogLevel.Info, `Job '${await job.getName()}' sent to path 1`);
            await job.sendToSingle("1");
        } else {
            await job.log(LogLevel.Info, `Job '${await job.getName()}' sent to path 2`);
            await job.sendToSingle("2");
        }
    } catch (error) {
        await job.fail(`Job processing failed due to an error: ${(error as Error).message}`);
    }
}



Here is the main.js code that's created when I run the transpile command:

Code: Select all

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.jobArrived = void 0;
/// <reference types="switch-scripting" />
const promises_1 = require("fs/promises");
const fast_xml_parser_1 = require("fast-xml-parser");
async function jobArrived(flowElement, job) {
    var _a, _b, _c, _d, _e, _f;
    try {
        // Retrieve the dataset
        const dataset = await job.getDataset('Processed DSF JDF', AccessLevel.ReadOnly);
        if (!dataset) {
            await job.log(LogLevel.Warning, "Dataset 'Processed DSF JDF' not found");
            await job.sendToSingle("2");
            return;
        }
        // Access the dataset file path
        const datasetPath = await job.get(AccessLevel.ReadOnly);
        if (!datasetPath) {
            await job.log(LogLevel.Warning, 'Unable to access dataset file');
            await job.sendToSingle("2");
            return;
        }
        // Read and parse the dataset XML
        const xmlContent = await (0, promises_1.readFile)(datasetPath, 'utf-8');
        const parser = new fast_xml_parser_1.XMLParser({ ignoreAttributes: false });
        const xmlData = parser.parse(xmlContent);
        // Navigate the parsed XML to get the UserFileName attribute
        const jdf = (_f = (_e = (_d = (_c = (_b = (_a = xmlData['dn:JDF']) === null || _a === void 0 ? void 0 : _a['dn:JDF']) === null || _b === void 0 ? void 0 : _b['dn:ResourcePool']) === null || _c === void 0 ? void 0 : _c['dn:RunList']) === null || _d === void 0 ? void 0 : _d['dn:RunList']) === null || _e === void 0 ? void 0 : _e['dn:LayoutElement']) === null || _f === void 0 ? void 0 : _f['dn:FileSpec'];
        const unparsedJobNumber = jdf === null || jdf === void 0 ? void 0 : jdf['@_UserFileName'];
        if (!unparsedJobNumber) {
            await job.log(LogLevel.Warning, 'Unable to retrieve job number from metadata');
            await job.sendToSingle("2");
            return;
        }
        const endPosition = unparsedJobNumber.toUpperCase().indexOf('.PDF');
        if (endPosition === -1) {
            await job.log(LogLevel.Warning, 'Job number format is incorrect');
            await job.sendToSingle("2");
            return;
        }
        const cleanedJobNumber = unparsedJobNumber.substring(0, endPosition);
        const parts = cleanedJobNumber.split('_');
        if (parts.length < 2) {
            await job.log(LogLevel.Warning, 'Job number format is incorrect');
            await job.sendToSingle("2");
            return;
        }
        const externalSubJobID = parts[1];
        // Send job to the appropriate output based on the sub-job ID
        if (externalSubJobID === '1') {
            await job.log(LogLevel.Info, `Job '${await job.getName()}' sent to path 1`);
            await job.sendToSingle("1");
        }
        else {
            await job.log(LogLevel.Info, `Job '${await job.getName()}' sent to path 2`);
            await job.sendToSingle("2");
        }
    }
    catch (error) {
        await job.fail(`Job processing failed due to an error: ${error.message}`);
    }
}
exports.jobArrived = jobArrived;
//# sourceMappingURL=main.js.map



Again, I'm new to this because I've been using Legacy Coding for years and now have to make the switch to Node.JS.

What am I missing? If you need more information or need to see code from other files, let me know. Also attached is a screenshot of my folder structure inside of VS Code.

Screenshot_179.png
Screenshot_179.png (149.51 KiB) Viewed 20048 times
freddyp
Advanced member
Posts: 1098
Joined: Thu Feb 09, 2012 3:53 pm

Re: undefined is not a function TypeError

Post by freddyp »

It will certainly be helpful to go through a debug session, so you can see exactly where in the code the problem pops up. If you do not know how to do that, please refer to the training videos in the Learn section of our website.

Glancing briefly over your code I suspect your problem lies with the querying of the XML. I recommend using the XmlDocument class that is part of the Switch scripting API. It is certainly easier to use than the package you are using:
https://www.enfocus.com/manuals/Develop ... thods.html

Sharing transpiled JavaScript code is not useful.
mkayyyy
Member
Posts: 95
Joined: Mon Nov 21, 2016 6:31 pm
Location: UK

Re: undefined is not a function TypeError

Post by mkayyyy »

The first thing that jumps out to me is the export declaration you've added to the jobArrived method, edit: also I noticed that you removed the s: Switch argument from the method too:

Code: Select all

export async function jobArrived(flowElement: FlowElement, job: Job) {
...
}
Remove the export declaration and add the s: Switch argument back in and that should solve the error:

Code: Select all

async function jobArrived(s: Switch, flowElement: FlowElement, job: Job) {
...
}
Last edited by mkayyyy on Wed Nov 13, 2024 10:47 am, edited 3 times in total.
freddyp
Advanced member
Posts: 1098
Joined: Thu Feb 09, 2012 3:53 pm

Re: undefined is not a function TypeError

Post by freddyp »

I missed that one. Good catch, Matthew.
dfsocha
Newbie
Posts: 15
Joined: Wed Aug 16, 2017 8:51 pm

Re: undefined is not a function TypeError

Post by dfsocha »

mkayyyy wrote: Wed Nov 13, 2024 10:42 am The first thing that jumps out to me is the export declaration you've added to the jobArrived method, edit: also I noticed that you removed the s: Switch argument from the method too:

Code: Select all

export async function jobArrived(flowElement: FlowElement, job: Job) {
...
}
Remove the export declaration and add the s: Switch argument back in and that should solve the error:

Code: Select all

async function jobArrived(s: Switch, flowElement: FlowElement, job: Job) {
...
}

Son of a biscuit.... that was it! Once I removed the export and added s: Switch, I also had to change the connection type from "Traffic Light" to "Move" and then it was able to move the file to the appropriate folder.

What I don't understand now is -- how does it know which path is path 1 and which path is path 2? I used to do that with a Traffic Light of Success on one and Warning on the other but now that's different.

Again, thank you so much! As soon as I entered that information, the script worked and the file was moved to the folder I wanted it to. I'm going to test some more files to make sure they all move to the correct folder as they're supposed to be split depending on the metadata in there.

I'm SO happy to see this working though. It's been a bit of a journey switching from Legacy to Node.JS but I will be happy when it's finally done :)
dfsocha
Newbie
Posts: 15
Joined: Wed Aug 16, 2017 8:51 pm

Re: undefined is not a function TypeError

Post by dfsocha »

freddyp wrote: Wed Nov 13, 2024 10:32 am It will certainly be helpful to go through a debug session, so you can see exactly where in the code the problem pops up. If you do not know how to do that, please refer to the training videos in the Learn section of our website.

Glancing briefly over your code I suspect your problem lies with the querying of the XML. I recommend using the XmlDocument class that is part of the Switch scripting API. It is certainly easier to use than the package you are using:
https://www.enfocus.com/manuals/Develop ... thods.html

Sharing transpiled JavaScript code is not useful.
Thank you. I will try the debug for future scripts. Will the debug session allow me to see something like the fact that I missed the s: Switch argument?
mkayyyy
Member
Posts: 95
Joined: Mon Nov 21, 2016 6:31 pm
Location: UK

Re: undefined is not a function TypeError

Post by mkayyyy »

dfsocha wrote: Wed Nov 13, 2024 3:37 pm
mkayyyy wrote: Wed Nov 13, 2024 10:42 am The first thing that jumps out to me is the export declaration you've added to the jobArrived method, edit: also I noticed that you removed the s: Switch argument from the method too:

Code: Select all

export async function jobArrived(flowElement: FlowElement, job: Job) {
...
}
Remove the export declaration and add the s: Switch argument back in and that should solve the error:

Code: Select all

async function jobArrived(s: Switch, flowElement: FlowElement, job: Job) {
...
}

Son of a biscuit.... that was it! Once I removed the export and added s: Switch, I also had to change the connection type from "Traffic Light" to "Move" and then it was able to move the file to the appropriate folder.

What I don't understand now is -- how does it know which path is path 1 and which path is path 2? I used to do that with a Traffic Light of Success on one and Warning on the other but now that's different.

Again, thank you so much! As soon as I entered that information, the script worked and the file was moved to the folder I wanted it to. I'm going to test some more files to make sure they all move to the correct folder as they're supposed to be split depending on the metadata in there.

I'm SO happy to see this working though. It's been a bit of a journey switching from Legacy to Node.JS but I will be happy when it's finally done :)
Glad I could help! If you're wanting to have Traffic Light outgoing connections you will need to use job.sendToData/sendToLog instead of job.sendToSingle and pass through the appropriate enums for the connection you want to send jobs to, for example:

Code: Select all

await job.sendToData(Connection.Level.Success);
await job.sendToData(Connection.Level.Warning);
await job.sendToData(Connection.Level.Error);
await job.sendToLog(Connection.Level.Success, DatasetModel.XML);
await job.sendToLog(Connection.Level.Warning, DatasetModel.XML);
await job.sendToLog(Connection.Level.Error, DatasetModel.XML);
dfsocha
Newbie
Posts: 15
Joined: Wed Aug 16, 2017 8:51 pm

Re: undefined is not a function TypeError

Post by dfsocha »

mkayyyy wrote: Wed Nov 13, 2024 3:44 pm
dfsocha wrote: Wed Nov 13, 2024 3:37 pm
mkayyyy wrote: Wed Nov 13, 2024 10:42 am The first thing that jumps out to me is the export declaration you've added to the jobArrived method, edit: also I noticed that you removed the s: Switch argument from the method too:

Code: Select all

export async function jobArrived(flowElement: FlowElement, job: Job) {
...
}
Remove the export declaration and add the s: Switch argument back in and that should solve the error:

Code: Select all

async function jobArrived(s: Switch, flowElement: FlowElement, job: Job) {
...
}

Son of a biscuit.... that was it! Once I removed the export and added s: Switch, I also had to change the connection type from "Traffic Light" to "Move" and then it was able to move the file to the appropriate folder.

What I don't understand now is -- how does it know which path is path 1 and which path is path 2? I used to do that with a Traffic Light of Success on one and Warning on the other but now that's different.

Again, thank you so much! As soon as I entered that information, the script worked and the file was moved to the folder I wanted it to. I'm going to test some more files to make sure they all move to the correct folder as they're supposed to be split depending on the metadata in there.

I'm SO happy to see this working though. It's been a bit of a journey switching from Legacy to Node.JS but I will be happy when it's finally done :)
Glad I could help! If you're wanting to have Traffic Light outgoing connections you will need to use job.sendToData/sendToLog instead of job.sendToSingle and pass through the appropriate enums for the connection you want to send jobs to, for example:

Code: Select all

await job.sendToData(Connection.Level.Success);
await job.sendToData(Connection.Level.Warning);
await job.sendToData(Connection.Level.Error);
await job.sendToLog(Connection.Level.Success, DatasetModel.XML);
await job.sendToLog(Connection.Level.Warning, DatasetModel.XML);
await job.sendToLog(Connection.Level.Error, DatasetModel.XML);


Thank you so much! I'm going to go try that now. I see the errors in my ways :D

Seriously, you've been such a big help. Thanks Matthew! :)
dfsocha
Newbie
Posts: 15
Joined: Wed Aug 16, 2017 8:51 pm

Re: undefined is not a function TypeError

Post by dfsocha »

OK - I've updated the sendtoData code and have it setup for success, warning and error paths.

freddyp mentioned using something different to read the XML file. I will have to look into that because as it stands right now, the script sends all files to the "error" path because it says the metadata doesn't include the information I'm looking for.

TL;DR -- I need to look at the meta data and pull out the file name - for example, 72895_XXX.pdf where XXX could be 1, 2 or any other sequence number depending on how many files there are. What this script should do is, for all file names that have _1, it should send it down "Connection.Level.Success" and if it's anything other than _1, it should go down .Warning.

Could it be that what I'm using to read the XML isn't correct? I'll look into the documentation on reading XML files and see what I might be missing.
mkayyyy
Member
Posts: 95
Joined: Mon Nov 21, 2016 6:31 pm
Location: UK

Re: undefined is not a function TypeError

Post by mkayyyy »

Have you got an example JDF/XML you could provide? That would make it easier to debug what's happening in your script
dfsocha
Newbie
Posts: 15
Joined: Wed Aug 16, 2017 8:51 pm

Re: undefined is not a function TypeError

Post by dfsocha »

mkayyyy wrote: Wed Nov 13, 2024 5:12 pm Have you got an example JDF/XML you could provide? That would make it easier to debug what's happening in your script
Sure! I've attached the MJD/JDF file (in xml format)
484633.zip
(2.49 KiB) Downloaded 117 times
mkayyyy
Member
Posts: 95
Joined: Mon Nov 21, 2016 6:31 pm
Location: UK

Re: undefined is not a function TypeError

Post by mkayyyy »

After debugging your script I think I was able to find your issue. The jdf variable you'd defined that queried the parsed xmlData was returning undefined

As you can see from the screenshot below when debugging the value of the xmlData variable the properties within it don't contain any "dn:" prefixes:
Image

I think all you need to do to get the code working as you expect is to update the this line:

Code: Select all

const jdf = xmlData['dn:JDF']?.['dn:JDF']?.['dn:ResourcePool']?.['dn:RunList']?.['dn:RunList']?.['dn:LayoutElement']?.['dn:FileSpec'];
to this:

Code: Select all

const jdf = xmlData['JDF']?.['JDF']?.['ResourcePool']?.['RunList']?.['RunList']?.['LayoutElement']?.['FileSpec'];
Post Reply