Skip to content

Commit f44e30c

Browse files
committed
feat: add line mode support
1 parent dccc721 commit f44e30c

File tree

3 files changed

+46
-49
lines changed

3 files changed

+46
-49
lines changed

README.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ parser.parseFile('example.nc', function(err, results) {
8080
### batchSize
8181

8282
Type: `Number`
83-
Default: `1000`
83+
Default: 1000
8484

8585
The batch size.
8686

@@ -99,16 +99,28 @@ parser.parseLine('G0 X0 Y0', { flatten: true });
9999
// => { line: 'G0 X0 Y0', words: [ 'G0', 'X0', 'Y0' ] }
100100
```
101101

102-
### noParseLine
102+
### lineMode
103103

104-
Type: `Boolean`
105-
Default: `false`
104+
Type: `String`
105+
Default: `'original'`
106+
107+
The `lineMode` option determines the format of the parsed line. It can be set to one of the following values:
108+
109+
- `'original'`: Returns the original line.
110+
- `'minimal'`: Returns the line without comments, but retains whitespace characters.
111+
- `'compact'`: Returns the line without comments and all whitespace characters.
106112

107-
True to not parse line, false otherwise.
113+
Example usage:
108114

109115
```js
110-
parser.parseFile('/path/to/file', { noParseLine: true }, function(err, results) {
111-
});
116+
parser.parseLine('G0 X0 Y0 ; comment', { lineMode: 'original' });
117+
// => { line: 'G0 X0 Y0 ; comment', words: [ [ 'G', 0 ], [ 'X', 0 ], [ 'Y', 0 ] ] }
118+
119+
parser.parseLine('G0 X0 Y0 ; comment', { lineMode: 'minimal' });
120+
// => { line: 'G0 X0 Y0', words: [ [ 'G', 0 ], [ 'X', 0 ], [ 'Y', 0 ] ] }
121+
122+
parser.parseLine('G0 X0 Y0 ; comment', { lineMode: 'compact' });
123+
// => { line: 'G0X0Y0', words: [ [ 'G', 0 ], [ 'X', 0 ], [ 'Y', 0 ] ] }
112124
```
113125

114126
## G-code Interpreter

src/__tests__/index.test.js

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,6 @@ describe('Pass an empty text as the first argument', () => {
4343
});
4444
});
4545

46-
describe('Contains only lines', () => {
47-
it('should not parse G-code commands.', (done) => {
48-
const filepath = path.resolve(__dirname, 'fixtures/circle.gcode');
49-
parseFile(filepath, { noParseLine: true }, (err, results) => {
50-
expect(results.length).toBe(7);
51-
done();
52-
})
53-
.on('data', (data) => {
54-
expect(typeof data).toBe('object');
55-
expect(typeof data.line).toBe('string');
56-
expect(data.words).toBe(undefined);
57-
})
58-
.on('end', (results) => {
59-
expect(results.length).toBe(7);
60-
});
61-
});
62-
});
63-
6446
describe('Invalid G-code words', () => {
6547
it('should ignore invalid g-code words', (done) => {
6648
const data = parseLine('messed up');

src/index.js

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -66,53 +66,61 @@ const parseLine = (() => {
6666
};
6767
// http://linuxcnc.org/docs/html/gcode/overview.html#gcode:comments
6868
// Comments can be embedded in a line using parentheses () or for the remainder of a lineusing a semi-colon. The semi-colon is not treated as the start of a comment when enclosed in parentheses.
69-
const stripAndExtractComments = (() => {
69+
const stripComments = (() => {
7070
// eslint-disable-next-line no-useless-escape
7171
const re1 = new RegExp(/\(([^\)]*)\)/g); // Match anything inside parentheses
7272
const re2 = new RegExp(/;(.*)$/g); // Match anything after a semi-colon to the end of the line
73-
const re3 = new RegExp(/\s+/g);
7473

7574
return (line) => {
7675
const comments = [];
7776
// Extract comments from parentheses
7877
line = line.replace(re1, (match, p1) => {
79-
const strippedLine = p1.trim();
80-
comments.push(strippedLine); // Add the match to comments
78+
const lineWithoutComments = p1.trim();
79+
comments.push(lineWithoutComments); // Add the match to comments
8180
return '';
8281
});
8382
// Extract comments after a semi-colon
8483
line = line.replace(re2, (match, p1) => {
85-
const strippedLine = p1.trim();
86-
comments.push(strippedLine); // Add the match to comments
84+
const lineWithoutComments = p1.trim();
85+
comments.push(lineWithoutComments); // Add the match to comments
8786
return '';
8887
});
89-
// Remove whitespace characters
90-
line = line.replace(re3, '');
88+
line = line.trim();
9189
return [line, comments];
9290
};
9391
})();
92+
93+
const stripWhitespace = (line) => {
94+
// Remove whitespace characters
95+
const re = new RegExp(/\s+/g);
96+
return line.replace(re, '');
97+
};
98+
9499
// eslint-disable-next-line no-useless-escape
95100
const re = /(%.*)|({.*)|((?:\$\$)|(?:\$[a-zA-Z0-9#]*))|([a-zA-Z][0-9\+\-\.]+)|(\*[0-9]+)/igm;
96101

97102
return (line, options) => {
98103
options = options || {};
99104
options.flatten = !!options.flatten;
100-
options.noParseLine = !!options.noParseLine;
105+
options.lineMode = options.lineMode ?? 'original'; // One of: 'original', 'minimal', 'compact'
101106

102107
const result = {
103-
line: line
108+
line: line,
109+
words: [],
104110
};
105111

106-
if (options.noParseLine) {
107-
return result;
108-
}
109-
110-
result.words = [];
111-
112112
let ln; // Line number
113113
let cs; // Checksum
114-
const [strippedLine, comments] = stripAndExtractComments(line);
115-
const words = strippedLine.match(re) || [];
114+
const [minimalLine, comments] = stripComments(line);
115+
const compactLine = stripWhitespace(minimalLine);
116+
117+
if (options.lineMode === 'minimal') {
118+
result.line = minimalLine;
119+
} else if (options.lineMode === 'compact') {
120+
result.line = compactLine;
121+
}
122+
123+
const words = compactLine.match(re) || [];
116124

117125
if (comments.length > 0) {
118126
result.comments = comments;
@@ -243,7 +251,7 @@ const parseString = (str, options, callback = noop) => {
243251
};
244252

245253
const parseStringSync = (str, options) => {
246-
const { flatten = false, noParseLine = false } = { ...options };
254+
const { flatten = false } = { ...options };
247255
const results = [];
248256
const lines = str.split('\n');
249257

@@ -254,7 +262,6 @@ const parseStringSync = (str, options) => {
254262
}
255263
const result = parseLine(line, {
256264
flatten,
257-
noParseLine
258265
});
259266
results.push(result);
260267
}
@@ -272,7 +279,6 @@ class GCodeLineStream extends Transform {
272279

273280
options = {
274281
batchSize: 1000,
275-
noParseLine: false
276282
};
277283

278284
lineBuffer = '';
@@ -282,7 +288,6 @@ class GCodeLineStream extends Transform {
282288
// @param {object} [options] The options object
283289
// @param {number} [options.batchSize] The batch size.
284290
// @param {boolean} [options.flatten] True to flatten the array, false otherwise.
285-
// @param {boolean} [options.noParseLine] True to not parse line, false otherwise.
286291
constructor(options = {}) {
287292
super({ objectMode: true });
288293

@@ -336,7 +341,6 @@ class GCodeLineStream extends Transform {
336341
if (line.length > 0) {
337342
const result = parseLine(line, {
338343
flatten: this.options.flatten,
339-
noParseLine: this.options.noParseLine
340344
});
341345
this.push(result);
342346
}
@@ -349,7 +353,6 @@ class GCodeLineStream extends Transform {
349353
if (line.length > 0) {
350354
const result = parseLine(line, {
351355
flatten: this.options.flatten,
352-
noParseLine: this.options.noParseLine
353356
});
354357
this.push(result);
355358
}

0 commit comments

Comments
 (0)