@dartfx/n8n-nodes-qsv 0.26.0 → 0.27.0-staging.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nodes/Qsv/Qsv.node.js +1 -1
- package/dist/nodes/Qsv/actions/executeClean.d.ts +2 -0
- package/dist/nodes/Qsv/actions/executeClean.js +147 -0
- package/dist/nodes/Qsv/actions/executeClipboard.d.ts +2 -0
- package/dist/nodes/Qsv/actions/executeClipboard.js +114 -0
- package/dist/nodes/Qsv/actions/executeColor.d.ts +2 -0
- package/dist/nodes/Qsv/actions/executeColor.js +126 -0
- package/dist/nodes/Qsv/actions/executeLens.d.ts +2 -0
- package/dist/nodes/Qsv/actions/executeLens.js +156 -0
- package/dist/nodes/Qsv/actions/executeLog.d.ts +2 -0
- package/dist/nodes/Qsv/actions/executeLog.js +111 -0
- package/dist/nodes/Qsv/actions/executePrompt.d.ts +2 -0
- package/dist/nodes/Qsv/actions/executePrompt.js +132 -0
- package/dist/nodes/Qsv/descriptions/CleanDescription.d.ts +2 -0
- package/dist/nodes/Qsv/descriptions/CleanDescription.js +140 -0
- package/dist/nodes/Qsv/descriptions/ClipboardDescription.d.ts +2 -0
- package/dist/nodes/Qsv/descriptions/ClipboardDescription.js +63 -0
- package/dist/nodes/Qsv/descriptions/ColorDescription.d.ts +2 -0
- package/dist/nodes/Qsv/descriptions/ColorDescription.js +91 -0
- package/dist/nodes/Qsv/descriptions/GetDescription.js +1 -1
- package/dist/nodes/Qsv/descriptions/LensDescription.d.ts +2 -0
- package/dist/nodes/Qsv/descriptions/LensDescription.js +161 -0
- package/dist/nodes/Qsv/descriptions/LogDescription.d.ts +2 -0
- package/dist/nodes/Qsv/descriptions/LogDescription.js +55 -0
- package/dist/nodes/Qsv/descriptions/PromptDescription.d.ts +2 -0
- package/dist/nodes/Qsv/descriptions/PromptDescription.js +105 -0
- package/dist/nodes/Qsv/descriptions/SchemaDescription.js +2 -2
- package/package.json +2 -2
|
@@ -156,7 +156,7 @@ class Qsv {
|
|
|
156
156
|
group: ['transform'],
|
|
157
157
|
version: 1,
|
|
158
158
|
subtitle: '={{$parameter["operation"]}}',
|
|
159
|
-
description: 'Ultra-fast tabular data wrangling, stats, and transformations via QSV (generated for QSV
|
|
159
|
+
description: 'Ultra-fast tabular data wrangling, stats, and transformations via QSV (generated for QSV 27.0.1; requires qsv CLI on host)',
|
|
160
160
|
defaults: {
|
|
161
161
|
name: 'QSV',
|
|
162
162
|
},
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeClean = executeClean;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const util_1 = require("util");
|
|
7
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
8
|
+
async function executeClean(itemIndex) {
|
|
9
|
+
const inputPath = this.getNodeParameter("inputPath", itemIndex);
|
|
10
|
+
if (!inputPath || !inputPath.trim()) {
|
|
11
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Input CSV file path is required.", { itemIndex });
|
|
12
|
+
}
|
|
13
|
+
const outputPath = this.getNodeParameter("outputPath", itemIndex, "") || "";
|
|
14
|
+
const additionalArgs = this.getNodeParameter("additionalArgs", itemIndex, "") || "";
|
|
15
|
+
const options = this.getNodeParameter("options", itemIndex, {}) || {};
|
|
16
|
+
const args = ["clean"];
|
|
17
|
+
if (options.stale === true) {
|
|
18
|
+
args.push("--stale");
|
|
19
|
+
}
|
|
20
|
+
if (options.recursive === true) {
|
|
21
|
+
args.push("--recursive");
|
|
22
|
+
}
|
|
23
|
+
if (options.dryRun === true) {
|
|
24
|
+
args.push("--dry-run");
|
|
25
|
+
}
|
|
26
|
+
if (options.force === true) {
|
|
27
|
+
args.push("--force");
|
|
28
|
+
}
|
|
29
|
+
if (options.index === true) {
|
|
30
|
+
args.push("--index");
|
|
31
|
+
}
|
|
32
|
+
if (options.stats === true) {
|
|
33
|
+
args.push("--stats");
|
|
34
|
+
}
|
|
35
|
+
if (options.frequency === true) {
|
|
36
|
+
args.push("--frequency");
|
|
37
|
+
}
|
|
38
|
+
if (options.schema === true) {
|
|
39
|
+
args.push("--schema");
|
|
40
|
+
}
|
|
41
|
+
if (options.validate === true) {
|
|
42
|
+
args.push("--validate");
|
|
43
|
+
}
|
|
44
|
+
if (options.moarstats === true) {
|
|
45
|
+
args.push("--moarstats");
|
|
46
|
+
}
|
|
47
|
+
if (options.all === true) {
|
|
48
|
+
args.push("--all");
|
|
49
|
+
}
|
|
50
|
+
if (options.quiet === true) {
|
|
51
|
+
args.push("--quiet");
|
|
52
|
+
}
|
|
53
|
+
if (additionalArgs.trim()) {
|
|
54
|
+
const rawMatches = additionalArgs.match(/[^\s"']+|"[^"]*"|'[^']*'/g) || [];
|
|
55
|
+
const parsedArgs = rawMatches.map((arg) => {
|
|
56
|
+
if ((arg.startsWith('"') && arg.endsWith('"')) ||
|
|
57
|
+
(arg.startsWith("'") && arg.endsWith("'"))) {
|
|
58
|
+
return arg.slice(1, -1);
|
|
59
|
+
}
|
|
60
|
+
return arg;
|
|
61
|
+
});
|
|
62
|
+
args.push(...parsedArgs);
|
|
63
|
+
}
|
|
64
|
+
if (outputPath.trim()) {
|
|
65
|
+
args.push("--output", outputPath.trim());
|
|
66
|
+
}
|
|
67
|
+
args.push(inputPath);
|
|
68
|
+
const qsvBin = process.env.DARTFX_QSV_BIN_PATH ||
|
|
69
|
+
process.env.QSV_BIN_PATH ||
|
|
70
|
+
process.env.QSV_PATH ||
|
|
71
|
+
"qsv";
|
|
72
|
+
try {
|
|
73
|
+
const { stdout, stderr } = await execFileAsync(qsvBin, args, {
|
|
74
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
75
|
+
encoding: "utf8",
|
|
76
|
+
});
|
|
77
|
+
let resultJson;
|
|
78
|
+
try {
|
|
79
|
+
resultJson = JSON.parse(stdout);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
resultJson = {
|
|
83
|
+
command: "qsv clean",
|
|
84
|
+
inputPath,
|
|
85
|
+
rawOutput: stdout,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const returnJson = {
|
|
89
|
+
success: true,
|
|
90
|
+
command: "clean",
|
|
91
|
+
inputPath,
|
|
92
|
+
result: resultJson,
|
|
93
|
+
};
|
|
94
|
+
if (outputPath.trim()) {
|
|
95
|
+
returnJson.outputPath = outputPath.trim();
|
|
96
|
+
}
|
|
97
|
+
if (stderr && stderr.trim()) {
|
|
98
|
+
returnJson.warnings = stderr.trim();
|
|
99
|
+
}
|
|
100
|
+
return [
|
|
101
|
+
{
|
|
102
|
+
json: returnJson,
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if (error.code === "ENOENT") {
|
|
108
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The QSV CLI binary ('${qsvBin}') was not found`, {
|
|
109
|
+
itemIndex,
|
|
110
|
+
description: `Please ensure 'qsv' is installed and available in the system PATH where n8n is running, or specify its absolute path via the DARTFX_QSV_BIN_PATH environment variable. (https://github.com/dathere/qsv)`,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (error.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ||
|
|
114
|
+
(error.message && error.message.includes("maxBuffer"))) {
|
|
115
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `QSV execution exceeded maximum stdout buffer (50 MB)`, {
|
|
116
|
+
itemIndex,
|
|
117
|
+
description: `qsv clean returned more data than could fit into memory. Specify an 'Output File Path' to stream results directly to disk instead.`,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
const rawError = (error.stderr || error.message || "").trim();
|
|
121
|
+
if (rawError.includes("is not a qsv command") ||
|
|
122
|
+
rawError.includes("unrecognized subcommand") ||
|
|
123
|
+
rawError.includes("not available in this")) {
|
|
124
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Operation 'clean' is not available in the installed QSV binary`, {
|
|
125
|
+
itemIndex,
|
|
126
|
+
description: `The installed QSV binary at '${qsvBin}' does not include the 'clean' feature. This feature may require a full feature build of QSV (e.g. qsv with all_features or a prebuilt binary with feature flags enabled). See https://github.com/dathere/qsv#feature-flags`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (rawError.includes("No such file or directory") ||
|
|
130
|
+
rawError.includes("os error 2")) {
|
|
131
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Input file not found: '${inputPath}'`, {
|
|
132
|
+
itemIndex,
|
|
133
|
+
description: `qsv clean could not find the file at '${inputPath}'. Check for typos, or if n8n is running in Docker, ensure the host directory is mounted into the container.`,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (rawError.includes("Operation not permitted") ||
|
|
137
|
+
rawError.includes("os error 1") ||
|
|
138
|
+
rawError.includes("Permission denied") ||
|
|
139
|
+
rawError.includes("os error 13")) {
|
|
140
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Permission denied accessing file: '${inputPath}'`, {
|
|
141
|
+
itemIndex,
|
|
142
|
+
description: `qsv clean was denied read access to '${inputPath}'. On macOS, check Full Disk Access or Removable Volumes permissions for the application running n8n.`,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed executing 'qsv clean': ${rawError}`, { itemIndex });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeClipboard = executeClipboard;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const util_1 = require("util");
|
|
7
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
8
|
+
async function executeClipboard(itemIndex) {
|
|
9
|
+
const inputPath = this.getNodeParameter("inputPath", itemIndex);
|
|
10
|
+
if (!inputPath || !inputPath.trim()) {
|
|
11
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Input CSV file path is required.", { itemIndex });
|
|
12
|
+
}
|
|
13
|
+
const outputPath = this.getNodeParameter("outputPath", itemIndex, "") || "";
|
|
14
|
+
const additionalArgs = this.getNodeParameter("additionalArgs", itemIndex, "") || "";
|
|
15
|
+
const options = this.getNodeParameter("options", itemIndex, {}) || {};
|
|
16
|
+
const args = ["clipboard"];
|
|
17
|
+
if (options.save === true) {
|
|
18
|
+
args.push("--save");
|
|
19
|
+
}
|
|
20
|
+
if (additionalArgs.trim()) {
|
|
21
|
+
const rawMatches = additionalArgs.match(/[^\s"']+|"[^"]*"|'[^']*'/g) || [];
|
|
22
|
+
const parsedArgs = rawMatches.map((arg) => {
|
|
23
|
+
if ((arg.startsWith('"') && arg.endsWith('"')) ||
|
|
24
|
+
(arg.startsWith("'") && arg.endsWith("'"))) {
|
|
25
|
+
return arg.slice(1, -1);
|
|
26
|
+
}
|
|
27
|
+
return arg;
|
|
28
|
+
});
|
|
29
|
+
args.push(...parsedArgs);
|
|
30
|
+
}
|
|
31
|
+
if (outputPath.trim()) {
|
|
32
|
+
args.push("--output", outputPath.trim());
|
|
33
|
+
}
|
|
34
|
+
args.push(inputPath);
|
|
35
|
+
const qsvBin = process.env.DARTFX_QSV_BIN_PATH ||
|
|
36
|
+
process.env.QSV_BIN_PATH ||
|
|
37
|
+
process.env.QSV_PATH ||
|
|
38
|
+
"qsv";
|
|
39
|
+
try {
|
|
40
|
+
const { stdout, stderr } = await execFileAsync(qsvBin, args, {
|
|
41
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
42
|
+
encoding: "utf8",
|
|
43
|
+
});
|
|
44
|
+
let resultJson;
|
|
45
|
+
try {
|
|
46
|
+
resultJson = JSON.parse(stdout);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
resultJson = {
|
|
50
|
+
command: "qsv clipboard",
|
|
51
|
+
inputPath,
|
|
52
|
+
rawOutput: stdout,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const returnJson = {
|
|
56
|
+
success: true,
|
|
57
|
+
command: "clipboard",
|
|
58
|
+
inputPath,
|
|
59
|
+
result: resultJson,
|
|
60
|
+
};
|
|
61
|
+
if (outputPath.trim()) {
|
|
62
|
+
returnJson.outputPath = outputPath.trim();
|
|
63
|
+
}
|
|
64
|
+
if (stderr && stderr.trim()) {
|
|
65
|
+
returnJson.warnings = stderr.trim();
|
|
66
|
+
}
|
|
67
|
+
return [
|
|
68
|
+
{
|
|
69
|
+
json: returnJson,
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (error.code === "ENOENT") {
|
|
75
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The QSV CLI binary ('${qsvBin}') was not found`, {
|
|
76
|
+
itemIndex,
|
|
77
|
+
description: `Please ensure 'qsv' is installed and available in the system PATH where n8n is running, or specify its absolute path via the DARTFX_QSV_BIN_PATH environment variable. (https://github.com/dathere/qsv)`,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (error.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ||
|
|
81
|
+
(error.message && error.message.includes("maxBuffer"))) {
|
|
82
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `QSV execution exceeded maximum stdout buffer (50 MB)`, {
|
|
83
|
+
itemIndex,
|
|
84
|
+
description: `qsv clipboard returned more data than could fit into memory. Specify an 'Output File Path' to stream results directly to disk instead.`,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const rawError = (error.stderr || error.message || "").trim();
|
|
88
|
+
if (rawError.includes("is not a qsv command") ||
|
|
89
|
+
rawError.includes("unrecognized subcommand") ||
|
|
90
|
+
rawError.includes("not available in this")) {
|
|
91
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Operation 'clipboard' is not available in the installed QSV binary`, {
|
|
92
|
+
itemIndex,
|
|
93
|
+
description: `The installed QSV binary at '${qsvBin}' does not include the 'clipboard' feature. This feature may require a full feature build of QSV (e.g. qsv with all_features or a prebuilt binary with feature flags enabled). See https://github.com/dathere/qsv#feature-flags`,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (rawError.includes("No such file or directory") ||
|
|
97
|
+
rawError.includes("os error 2")) {
|
|
98
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Input file not found: '${inputPath}'`, {
|
|
99
|
+
itemIndex,
|
|
100
|
+
description: `qsv clipboard could not find the file at '${inputPath}'. Check for typos, or if n8n is running in Docker, ensure the host directory is mounted into the container.`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (rawError.includes("Operation not permitted") ||
|
|
104
|
+
rawError.includes("os error 1") ||
|
|
105
|
+
rawError.includes("Permission denied") ||
|
|
106
|
+
rawError.includes("os error 13")) {
|
|
107
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Permission denied accessing file: '${inputPath}'`, {
|
|
108
|
+
itemIndex,
|
|
109
|
+
description: `qsv clipboard was denied read access to '${inputPath}'. On macOS, check Full Disk Access or Removable Volumes permissions for the application running n8n.`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed executing 'qsv clipboard': ${rawError}`, { itemIndex });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeColor = executeColor;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const util_1 = require("util");
|
|
7
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
8
|
+
async function executeColor(itemIndex) {
|
|
9
|
+
const inputPath = this.getNodeParameter("inputPath", itemIndex);
|
|
10
|
+
if (!inputPath || !inputPath.trim()) {
|
|
11
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Input CSV file path is required.", { itemIndex });
|
|
12
|
+
}
|
|
13
|
+
const outputPath = this.getNodeParameter("outputPath", itemIndex, "") || "";
|
|
14
|
+
const additionalArgs = this.getNodeParameter("additionalArgs", itemIndex, "") || "";
|
|
15
|
+
const options = this.getNodeParameter("options", itemIndex, {}) || {};
|
|
16
|
+
const args = ["color"];
|
|
17
|
+
if (options.color === true) {
|
|
18
|
+
args.push("--color");
|
|
19
|
+
}
|
|
20
|
+
if (options.rowNumbers === true) {
|
|
21
|
+
args.push("--row-numbers");
|
|
22
|
+
}
|
|
23
|
+
if (options.title !== undefined && options.title !== "") {
|
|
24
|
+
args.push("--title", String(options.title));
|
|
25
|
+
}
|
|
26
|
+
if (options.delimiter !== undefined && options.delimiter !== "") {
|
|
27
|
+
args.push("--delimiter", String(options.delimiter));
|
|
28
|
+
}
|
|
29
|
+
if (options.memcheck === true) {
|
|
30
|
+
args.push("--memcheck");
|
|
31
|
+
}
|
|
32
|
+
if (additionalArgs.trim()) {
|
|
33
|
+
const rawMatches = additionalArgs.match(/[^\s"']+|"[^"]*"|'[^']*'/g) || [];
|
|
34
|
+
const parsedArgs = rawMatches.map((arg) => {
|
|
35
|
+
if ((arg.startsWith('"') && arg.endsWith('"')) ||
|
|
36
|
+
(arg.startsWith("'") && arg.endsWith("'"))) {
|
|
37
|
+
return arg.slice(1, -1);
|
|
38
|
+
}
|
|
39
|
+
return arg;
|
|
40
|
+
});
|
|
41
|
+
args.push(...parsedArgs);
|
|
42
|
+
}
|
|
43
|
+
if (outputPath.trim()) {
|
|
44
|
+
args.push("--output", outputPath.trim());
|
|
45
|
+
}
|
|
46
|
+
args.push(inputPath);
|
|
47
|
+
const qsvBin = process.env.DARTFX_QSV_BIN_PATH ||
|
|
48
|
+
process.env.QSV_BIN_PATH ||
|
|
49
|
+
process.env.QSV_PATH ||
|
|
50
|
+
"qsv";
|
|
51
|
+
try {
|
|
52
|
+
const { stdout, stderr } = await execFileAsync(qsvBin, args, {
|
|
53
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
54
|
+
encoding: "utf8",
|
|
55
|
+
});
|
|
56
|
+
let resultJson;
|
|
57
|
+
try {
|
|
58
|
+
resultJson = JSON.parse(stdout);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
resultJson = {
|
|
62
|
+
command: "qsv color",
|
|
63
|
+
inputPath,
|
|
64
|
+
rawOutput: stdout,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const returnJson = {
|
|
68
|
+
success: true,
|
|
69
|
+
command: "color",
|
|
70
|
+
inputPath,
|
|
71
|
+
result: resultJson,
|
|
72
|
+
};
|
|
73
|
+
if (outputPath.trim()) {
|
|
74
|
+
returnJson.outputPath = outputPath.trim();
|
|
75
|
+
}
|
|
76
|
+
if (stderr && stderr.trim()) {
|
|
77
|
+
returnJson.warnings = stderr.trim();
|
|
78
|
+
}
|
|
79
|
+
return [
|
|
80
|
+
{
|
|
81
|
+
json: returnJson,
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (error.code === "ENOENT") {
|
|
87
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The QSV CLI binary ('${qsvBin}') was not found`, {
|
|
88
|
+
itemIndex,
|
|
89
|
+
description: `Please ensure 'qsv' is installed and available in the system PATH where n8n is running, or specify its absolute path via the DARTFX_QSV_BIN_PATH environment variable. (https://github.com/dathere/qsv)`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (error.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ||
|
|
93
|
+
(error.message && error.message.includes("maxBuffer"))) {
|
|
94
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `QSV execution exceeded maximum stdout buffer (50 MB)`, {
|
|
95
|
+
itemIndex,
|
|
96
|
+
description: `qsv color returned more data than could fit into memory. Specify an 'Output File Path' to stream results directly to disk instead.`,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
const rawError = (error.stderr || error.message || "").trim();
|
|
100
|
+
if (rawError.includes("is not a qsv command") ||
|
|
101
|
+
rawError.includes("unrecognized subcommand") ||
|
|
102
|
+
rawError.includes("not available in this")) {
|
|
103
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Operation 'color' is not available in the installed QSV binary`, {
|
|
104
|
+
itemIndex,
|
|
105
|
+
description: `The installed QSV binary at '${qsvBin}' does not include the 'color' feature. This feature may require a full feature build of QSV (e.g. qsv with all_features or a prebuilt binary with feature flags enabled). See https://github.com/dathere/qsv#feature-flags`,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
if (rawError.includes("No such file or directory") ||
|
|
109
|
+
rawError.includes("os error 2")) {
|
|
110
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Input file not found: '${inputPath}'`, {
|
|
111
|
+
itemIndex,
|
|
112
|
+
description: `qsv color could not find the file at '${inputPath}'. Check for typos, or if n8n is running in Docker, ensure the host directory is mounted into the container.`,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (rawError.includes("Operation not permitted") ||
|
|
116
|
+
rawError.includes("os error 1") ||
|
|
117
|
+
rawError.includes("Permission denied") ||
|
|
118
|
+
rawError.includes("os error 13")) {
|
|
119
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Permission denied accessing file: '${inputPath}'`, {
|
|
120
|
+
itemIndex,
|
|
121
|
+
description: `qsv color was denied read access to '${inputPath}'. On macOS, check Full Disk Access or Removable Volumes permissions for the application running n8n.`,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed executing 'qsv color': ${rawError}`, { itemIndex });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeLens = executeLens;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const util_1 = require("util");
|
|
7
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
8
|
+
async function executeLens(itemIndex) {
|
|
9
|
+
const inputPath = this.getNodeParameter("inputPath", itemIndex);
|
|
10
|
+
if (!inputPath || !inputPath.trim()) {
|
|
11
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Input CSV file path is required.", { itemIndex });
|
|
12
|
+
}
|
|
13
|
+
const outputPath = this.getNodeParameter("outputPath", itemIndex, "") || "";
|
|
14
|
+
const additionalArgs = this.getNodeParameter("additionalArgs", itemIndex, "") || "";
|
|
15
|
+
const options = this.getNodeParameter("options", itemIndex, {}) || {};
|
|
16
|
+
const args = ["lens"];
|
|
17
|
+
if (options.delimiter !== undefined && options.delimiter !== "") {
|
|
18
|
+
args.push("--delimiter", String(options.delimiter));
|
|
19
|
+
}
|
|
20
|
+
if (options.tabSeparated === true) {
|
|
21
|
+
args.push("--tab-separated");
|
|
22
|
+
}
|
|
23
|
+
if (options.noHeaders === true) {
|
|
24
|
+
args.push("--no-headers");
|
|
25
|
+
}
|
|
26
|
+
if (options.columns !== undefined && options.columns !== "") {
|
|
27
|
+
args.push("--columns", String(options.columns));
|
|
28
|
+
}
|
|
29
|
+
if (options.filter !== undefined && options.filter !== "") {
|
|
30
|
+
args.push("--filter", String(options.filter));
|
|
31
|
+
}
|
|
32
|
+
if (options.find !== undefined && options.find !== "") {
|
|
33
|
+
args.push("--find", String(options.find));
|
|
34
|
+
}
|
|
35
|
+
if (options.ignoreCase === true) {
|
|
36
|
+
args.push("--ignore-case");
|
|
37
|
+
}
|
|
38
|
+
if (options.freezeColumns !== undefined && options.freezeColumns !== "") {
|
|
39
|
+
args.push("--freeze-columns", String(options.freezeColumns));
|
|
40
|
+
}
|
|
41
|
+
if (options.monochrome === true) {
|
|
42
|
+
args.push("--monochrome");
|
|
43
|
+
}
|
|
44
|
+
if (options.wrapMode !== undefined && options.wrapMode !== "") {
|
|
45
|
+
args.push("--wrap-mode", String(options.wrapMode));
|
|
46
|
+
}
|
|
47
|
+
if (options.autoReload === true) {
|
|
48
|
+
args.push("--auto-reload");
|
|
49
|
+
}
|
|
50
|
+
if (options.streamingStdin === true) {
|
|
51
|
+
args.push("--streaming-stdin");
|
|
52
|
+
}
|
|
53
|
+
if (options.prompt !== undefined && options.prompt !== "") {
|
|
54
|
+
args.push("--prompt", String(options.prompt));
|
|
55
|
+
}
|
|
56
|
+
if (options.echoColumn !== undefined && options.echoColumn !== "") {
|
|
57
|
+
args.push("--echo-column", String(options.echoColumn));
|
|
58
|
+
}
|
|
59
|
+
if (options.debug === true) {
|
|
60
|
+
args.push("--debug");
|
|
61
|
+
}
|
|
62
|
+
if (additionalArgs.trim()) {
|
|
63
|
+
const rawMatches = additionalArgs.match(/[^\s"']+|"[^"]*"|'[^']*'/g) || [];
|
|
64
|
+
const parsedArgs = rawMatches.map((arg) => {
|
|
65
|
+
if ((arg.startsWith('"') && arg.endsWith('"')) ||
|
|
66
|
+
(arg.startsWith("'") && arg.endsWith("'"))) {
|
|
67
|
+
return arg.slice(1, -1);
|
|
68
|
+
}
|
|
69
|
+
return arg;
|
|
70
|
+
});
|
|
71
|
+
args.push(...parsedArgs);
|
|
72
|
+
}
|
|
73
|
+
if (outputPath.trim()) {
|
|
74
|
+
args.push("--output", outputPath.trim());
|
|
75
|
+
}
|
|
76
|
+
args.push(inputPath);
|
|
77
|
+
const qsvBin = process.env.DARTFX_QSV_BIN_PATH ||
|
|
78
|
+
process.env.QSV_BIN_PATH ||
|
|
79
|
+
process.env.QSV_PATH ||
|
|
80
|
+
"qsv";
|
|
81
|
+
try {
|
|
82
|
+
const { stdout, stderr } = await execFileAsync(qsvBin, args, {
|
|
83
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
84
|
+
encoding: "utf8",
|
|
85
|
+
});
|
|
86
|
+
let resultJson;
|
|
87
|
+
try {
|
|
88
|
+
resultJson = JSON.parse(stdout);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
resultJson = {
|
|
92
|
+
command: "qsv lens",
|
|
93
|
+
inputPath,
|
|
94
|
+
rawOutput: stdout,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const returnJson = {
|
|
98
|
+
success: true,
|
|
99
|
+
command: "lens",
|
|
100
|
+
inputPath,
|
|
101
|
+
result: resultJson,
|
|
102
|
+
};
|
|
103
|
+
if (outputPath.trim()) {
|
|
104
|
+
returnJson.outputPath = outputPath.trim();
|
|
105
|
+
}
|
|
106
|
+
if (stderr && stderr.trim()) {
|
|
107
|
+
returnJson.warnings = stderr.trim();
|
|
108
|
+
}
|
|
109
|
+
return [
|
|
110
|
+
{
|
|
111
|
+
json: returnJson,
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error.code === "ENOENT") {
|
|
117
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The QSV CLI binary ('${qsvBin}') was not found`, {
|
|
118
|
+
itemIndex,
|
|
119
|
+
description: `Please ensure 'qsv' is installed and available in the system PATH where n8n is running, or specify its absolute path via the DARTFX_QSV_BIN_PATH environment variable. (https://github.com/dathere/qsv)`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (error.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ||
|
|
123
|
+
(error.message && error.message.includes("maxBuffer"))) {
|
|
124
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `QSV execution exceeded maximum stdout buffer (50 MB)`, {
|
|
125
|
+
itemIndex,
|
|
126
|
+
description: `qsv lens returned more data than could fit into memory. Specify an 'Output File Path' to stream results directly to disk instead.`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const rawError = (error.stderr || error.message || "").trim();
|
|
130
|
+
if (rawError.includes("is not a qsv command") ||
|
|
131
|
+
rawError.includes("unrecognized subcommand") ||
|
|
132
|
+
rawError.includes("not available in this")) {
|
|
133
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Operation 'lens' is not available in the installed QSV binary`, {
|
|
134
|
+
itemIndex,
|
|
135
|
+
description: `The installed QSV binary at '${qsvBin}' does not include the 'lens' feature. This feature may require a full feature build of QSV (e.g. qsv with all_features or a prebuilt binary with feature flags enabled). See https://github.com/dathere/qsv#feature-flags`,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (rawError.includes("No such file or directory") ||
|
|
139
|
+
rawError.includes("os error 2")) {
|
|
140
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Input file not found: '${inputPath}'`, {
|
|
141
|
+
itemIndex,
|
|
142
|
+
description: `qsv lens could not find the file at '${inputPath}'. Check for typos, or if n8n is running in Docker, ensure the host directory is mounted into the container.`,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
if (rawError.includes("Operation not permitted") ||
|
|
146
|
+
rawError.includes("os error 1") ||
|
|
147
|
+
rawError.includes("Permission denied") ||
|
|
148
|
+
rawError.includes("os error 13")) {
|
|
149
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Permission denied accessing file: '${inputPath}'`, {
|
|
150
|
+
itemIndex,
|
|
151
|
+
description: `qsv lens was denied read access to '${inputPath}'. On macOS, check Full Disk Access or Removable Volumes permissions for the application running n8n.`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed executing 'qsv lens': ${rawError}`, { itemIndex });
|
|
155
|
+
}
|
|
156
|
+
}
|