@dartfx/n8n-nodes-qsv 0.2.1 → 0.26.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.
Files changed (54) hide show
  1. package/dist/nodes/Qsv/Qsv.node.js +2 -2
  2. package/dist/nodes/Qsv/actions/executeClean.d.ts +2 -0
  3. package/dist/nodes/Qsv/actions/executeClean.js +147 -0
  4. package/dist/nodes/Qsv/actions/executeClipboard.d.ts +2 -0
  5. package/dist/nodes/Qsv/actions/executeClipboard.js +114 -0
  6. package/dist/nodes/Qsv/actions/executeColor.d.ts +2 -0
  7. package/dist/nodes/Qsv/actions/executeColor.js +126 -0
  8. package/dist/nodes/Qsv/actions/executeCount.js +0 -3
  9. package/dist/nodes/Qsv/actions/executeGeocode.js +15 -0
  10. package/dist/nodes/Qsv/actions/executeGeoconvert.js +3 -0
  11. package/dist/nodes/Qsv/actions/executeJoinp.js +0 -3
  12. package/dist/nodes/Qsv/actions/executeLens.d.ts +2 -0
  13. package/dist/nodes/Qsv/actions/executeLens.js +156 -0
  14. package/dist/nodes/Qsv/actions/executeLog.d.ts +2 -0
  15. package/dist/nodes/Qsv/actions/executeLog.js +111 -0
  16. package/dist/nodes/Qsv/actions/executePivotp.js +3 -0
  17. package/dist/nodes/Qsv/actions/executePrompt.d.ts +2 -0
  18. package/dist/nodes/Qsv/actions/executePrompt.js +132 -0
  19. package/dist/nodes/Qsv/actions/executeSqlp.js +0 -3
  20. package/dist/nodes/Qsv/actions/executeValidate.js +3 -0
  21. package/dist/nodes/Qsv/actions/executeViz.js +12 -0
  22. package/dist/nodes/Qsv/descriptions/CatDescription.js +1 -1
  23. package/dist/nodes/Qsv/descriptions/CleanDescription.d.ts +2 -0
  24. package/dist/nodes/Qsv/descriptions/CleanDescription.js +140 -0
  25. package/dist/nodes/Qsv/descriptions/ClipboardDescription.d.ts +2 -0
  26. package/dist/nodes/Qsv/descriptions/ClipboardDescription.js +63 -0
  27. package/dist/nodes/Qsv/descriptions/ColorDescription.d.ts +2 -0
  28. package/dist/nodes/Qsv/descriptions/ColorDescription.js +91 -0
  29. package/dist/nodes/Qsv/descriptions/CountDescription.js +2 -9
  30. package/dist/nodes/Qsv/descriptions/DescribegptDescription.js +1 -1
  31. package/dist/nodes/Qsv/descriptions/ExcelDescription.js +2 -2
  32. package/dist/nodes/Qsv/descriptions/FrequencyDescription.js +3 -3
  33. package/dist/nodes/Qsv/descriptions/GeocodeDescription.js +55 -16
  34. package/dist/nodes/Qsv/descriptions/GeoconvertDescription.js +8 -1
  35. package/dist/nodes/Qsv/descriptions/GetDescription.js +1 -1
  36. package/dist/nodes/Qsv/descriptions/JoinpDescription.js +1 -8
  37. package/dist/nodes/Qsv/descriptions/JsonlDescription.js +2 -2
  38. package/dist/nodes/Qsv/descriptions/LensDescription.d.ts +2 -0
  39. package/dist/nodes/Qsv/descriptions/LensDescription.js +161 -0
  40. package/dist/nodes/Qsv/descriptions/LogDescription.d.ts +2 -0
  41. package/dist/nodes/Qsv/descriptions/LogDescription.js +55 -0
  42. package/dist/nodes/Qsv/descriptions/PivotpDescription.js +10 -3
  43. package/dist/nodes/Qsv/descriptions/PromptDescription.d.ts +2 -0
  44. package/dist/nodes/Qsv/descriptions/PromptDescription.js +105 -0
  45. package/dist/nodes/Qsv/descriptions/ReadstatDescription.js +2 -2
  46. package/dist/nodes/Qsv/descriptions/SchemaDescription.js +1 -1
  47. package/dist/nodes/Qsv/descriptions/ScoresqlDescription.js +2 -2
  48. package/dist/nodes/Qsv/descriptions/SqlpDescription.js +3 -10
  49. package/dist/nodes/Qsv/descriptions/StatsDescription.js +2 -2
  50. package/dist/nodes/Qsv/descriptions/TemplateDescription.js +2 -2
  51. package/dist/nodes/Qsv/descriptions/ToDescription.js +1 -1
  52. package/dist/nodes/Qsv/descriptions/ValidateDescription.js +9 -2
  53. package/dist/nodes/Qsv/descriptions/VizDescription.js +40 -9
  54. package/package.json +6 -1
@@ -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 24.0.0; requires qsv CLI on host)',
159
+ description: 'Ultra-fast tabular data wrangling, stats, and transformations via QSV (generated for QSV 26.0.0; requires qsv CLI on host)',
160
160
  defaults: {
161
161
  name: 'QSV',
162
162
  },
@@ -328,7 +328,7 @@ class Qsv {
328
328
  {
329
329
  name: 'Geocode (geocode) [Feature: geocode]',
330
330
  value: 'geocode',
331
- description: 'Geocodes a location against an updatable local copy of the Geonames cities & the Maxmind GeoLite2 databases — with caching and multi-threading, this offline path geocodes up to 360,000 records/sec! Can also geocode online (forward & reverse) via the OpenCage geocoder. (Category: utility | Docs: https://github.com/dathere/qsv/blob/master/docs/help/geocode.md)',
331
+ description: 'Geocodes a location against an updatable local copy of the Geonames cities & the Maxmind GeoLite2 databases — with caching and multi-threading, this offline path geocodes up to 360,000 records/sec! Can also geocode online (forward & reverse) via the OpenCage geocoder, geocode New York City addresses, BBLs and BINs via NYC\'s Geoclient API, which also returns NYC attributes such as council districts and census tracts, and geocode US addresses & coordinates via the free US Census Geocoder - single or batch - returning Census state, county, tract, block group & block GEOIDs for Census data enrichment. (Category: utility | Docs: https://github.com/dathere/qsv/blob/master/docs/help/geocode.md)',
332
332
  action: 'Geocode',
333
333
  },
334
334
  {
@@ -0,0 +1,2 @@
1
+ import type { IExecuteFunctions, INodeExecutionData } from "n8n-workflow";
2
+ export declare function executeClean(this: IExecuteFunctions, itemIndex: number): Promise<INodeExecutionData[]>;
@@ -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,2 @@
1
+ import type { IExecuteFunctions, INodeExecutionData } from "n8n-workflow";
2
+ export declare function executeClipboard(this: IExecuteFunctions, itemIndex: number): Promise<INodeExecutionData[]>;
@@ -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,2 @@
1
+ import type { IExecuteFunctions, INodeExecutionData } from "n8n-workflow";
2
+ export declare function executeColor(this: IExecuteFunctions, itemIndex: number): Promise<INodeExecutionData[]>;
@@ -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
+ }
@@ -26,9 +26,6 @@ async function executeCount(itemIndex) {
26
26
  if (options.json === true) {
27
27
  args.push('--json');
28
28
  }
29
- if (options.lowMemory === true) {
30
- args.push('--low-memory');
31
- }
32
29
  if (options.noHeaders === true) {
33
30
  args.push('--no-headers');
34
31
  }
@@ -30,12 +30,18 @@ async function executeGeocode(itemIndex) {
30
30
  if (options.batch !== undefined && options.batch !== '') {
31
31
  args.push('--batch', String(options.batch));
32
32
  }
33
+ if (options.benchmark !== undefined && options.benchmark !== '') {
34
+ args.push('--benchmark', String(options.benchmark));
35
+ }
33
36
  if (options.cacheDir !== undefined && options.cacheDir !== '') {
34
37
  args.push('--cache-dir', String(options.cacheDir));
35
38
  }
36
39
  if (options.cacheTtl !== undefined && options.cacheTtl !== '') {
37
40
  args.push('--cache-ttl', String(options.cacheTtl));
38
41
  }
42
+ if (options.censusMode !== undefined && options.censusMode !== '') {
43
+ args.push('--census-mode', String(options.censusMode));
44
+ }
39
45
  if (options.citiesUrl !== undefined && options.citiesUrl !== '') {
40
46
  args.push('--cities-url', String(options.citiesUrl));
41
47
  }
@@ -45,6 +51,9 @@ async function executeGeocode(itemIndex) {
45
51
  if (options.delimiter !== undefined && options.delimiter !== '') {
46
52
  args.push('--delimiter', String(options.delimiter));
47
53
  }
54
+ if (options.endpoint !== undefined && options.endpoint !== '') {
55
+ args.push('--endpoint', String(options.endpoint));
56
+ }
48
57
  if (options.force === true) {
49
58
  args.push('--force');
50
59
  }
@@ -78,6 +87,9 @@ async function executeGeocode(itemIndex) {
78
87
  if (options.olderThan !== undefined && options.olderThan !== '') {
79
88
  args.push('--older-than', String(options.olderThan));
80
89
  }
90
+ if (options.params !== undefined && options.params !== '') {
91
+ args.push('--params', String(options.params));
92
+ }
81
93
  if (options.rateLimit !== undefined && options.rateLimit !== '') {
82
94
  args.push('--rate-limit', String(options.rateLimit));
83
95
  }
@@ -90,6 +102,9 @@ async function executeGeocode(itemIndex) {
90
102
  if (options.timeout !== undefined && options.timeout !== '') {
91
103
  args.push('--timeout', String(options.timeout));
92
104
  }
105
+ if (options.vintage !== undefined && options.vintage !== '') {
106
+ args.push('--vintage', String(options.vintage));
107
+ }
93
108
  if (additionalArgs.trim()) {
94
109
  const rawMatches = additionalArgs.match(/[^\s"']+|"[^"]*"|'[^']*'/g) || [];
95
110
  const parsedArgs = rawMatches.map((arg) => {
@@ -22,6 +22,9 @@ async function executeGeoconvert(itemIndex) {
22
22
  const additionalArgs = this.getNodeParameter('additionalArgs', itemIndex, '') || '';
23
23
  const options = this.getNodeParameter('options', itemIndex, {}) || {};
24
24
  const args = ['geoconvert'];
25
+ if (options.delimiter !== undefined && options.delimiter !== '') {
26
+ args.push('--delimiter', String(options.delimiter));
27
+ }
25
28
  if (options.geometry !== undefined && options.geometry !== '') {
26
29
  args.push('--geometry', String(options.geometry));
27
30
  }
@@ -83,9 +83,6 @@ async function executeJoinp(itemIndex) {
83
83
  if (options.left_by !== undefined && options.left_by !== '') {
84
84
  args.push('--left_by', String(options.left_by));
85
85
  }
86
- if (options.lowMemory === true) {
87
- args.push('--low-memory');
88
- }
89
86
  if (options.maintainOrder !== undefined && options.maintainOrder !== '') {
90
87
  args.push('--maintain-order', String(options.maintainOrder));
91
88
  }
@@ -0,0 +1,2 @@
1
+ import type { IExecuteFunctions, INodeExecutionData } from "n8n-workflow";
2
+ export declare function executeLens(this: IExecuteFunctions, itemIndex: number): Promise<INodeExecutionData[]>;
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ import type { IExecuteFunctions, INodeExecutionData } from "n8n-workflow";
2
+ export declare function executeLog(this: IExecuteFunctions, itemIndex: number): Promise<INodeExecutionData[]>;