Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: exports stripComments #10

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/__tests__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
parseString,
parseStringSync,
parseFile,
parseFileSync
parseFileSync,
stripComments,
} from '..';

describe('Pass a null value as the first argument', () => {
Expand Down Expand Up @@ -148,6 +149,7 @@ describe('Commands', () => {
describe('Stripping comments', () => {
it('should correctly parse a semicolon comment before parentheses', () => {
const line = 'M6 ; comment (tool change) T1';
expect(stripComments(line)).toBe('M6');
const data = parseLine(line, { lineMode: 'stripped' });
expect(data.line).toBe('M6');
expect(data.comments).toEqual([
Expand All @@ -157,6 +159,7 @@ describe('Stripping comments', () => {

it('should correctly parse nested parentheses containing a semicolon', () => {
const line = 'M6 (outer (inner;)) T1 ; comment';
expect(stripComments(line)).toBe('M6 T1');
const data = parseLine(line, { lineMode: 'stripped' });
expect(data.line).toBe('M6 T1');
expect(data.comments).toEqual([
Expand All @@ -167,6 +170,7 @@ describe('Stripping comments', () => {

it('should correctly parse multiple comments in a line', () => {
const line = 'M6 (first comment) T1 ; second comment';
expect(stripComments(line)).toBe('M6 T1');
const data = parseLine(line, { lineMode: 'stripped' });
expect(data.line).toBe('M6 T1');
expect(data.comments).toEqual([
Expand Down
152 changes: 76 additions & 76 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,87 +60,86 @@ const iterateArray = (arr = [], opts = {}, iteratee = noop, done = noop) => {
loop();
};

// @param {string} line The G-code line
const parseLine = (() => {
// http://reprap.org/wiki/G-code#Special_fields
// The checksum "cs" for a GCode string "cmd" (including its line number) is computed
// by exor-ing the bytes in the string up to and not including the * character.
const computeChecksum = (s) => {
s = s || '';
if (s.lastIndexOf('*') >= 0) {
s = s.substr(0, s.lastIndexOf('*'));
}
// http://reprap.org/wiki/G-code#Special_fields
// The checksum "cs" for a GCode string "cmd" (including its line number) is computed
// by exor-ing the bytes in the string up to and not including the * character.
const computeChecksum = (s) => {
s = s || '';
if (s.lastIndexOf('*') >= 0) {
s = s.substr(0, s.lastIndexOf('*'));
}

let cs = 0;
for (let i = 0; i < s.length; ++i) {
const c = s[i].charCodeAt(0);
cs ^= c;
}
return cs;
};
let cs = 0;
for (let i = 0; i < s.length; ++i) {
const c = s[i].charCodeAt(0);
cs ^= c;
}
return cs;
};

// Strips comments from a G-code line and returns stripped line and comments.
const stripCommentsEx = (line) => {
// http://linuxcnc.org/docs/html/gcode/overview.html#gcode:comments
// 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.
const stripComments = (() => {
const _stripComments = (line) => {
let result = '';
let currentComment = '';
let comments = [];
let openParens = 0;

// Detect semicolon comments before parentheses
for (let i = 0; i < line.length; i++) {
const char = line[i];

if (char === ';' && openParens === 0) {
// Start semicolon comment outside parentheses
comments.push(line.slice(i + 1).trim());
openParens = 0; // Reset parentheses counter
break; // Stop further processing after a semicolon comment
}

if (char === '(') {
// Start parentheses comment
if (openParens === 0) {
currentComment = '';
} else if (openParens > 0) {
currentComment += char;
}
openParens = Math.min(openParens + 1, Number.MAX_SAFE_INTEGER);
} else if (char === ')') {
// End parentheses comment
openParens = Math.max(0, openParens - 1);
if (openParens === 0) {
comments.push(currentComment.trim());
currentComment = '';
} else if (openParens > 0) {
currentComment += char;
}
} else if (openParens > 0) {
// Inside parentheses comment
currentComment += char;
} else {
// Normal text outside comments
result += char;
}
// Comments can be included in a line using either parentheses "()" or a semicolon ";" to mark the rest of the line.
// If a semicolon is enclosed within parentheses, it is not interpreted as the start of a comment.
let strippedLine = '';
let currentComment = '';
let comments = [];
let openParens = 0;

// Detect semicolon comments before parentheses
for (let i = 0; i < line.length; i++) {
const char = line[i];

if (char === ';' && openParens === 0) {
// Start semicolon comment outside parentheses
comments.push(line.slice(i + 1).trim());
openParens = 0; // Reset parentheses counter
break; // Stop further processing after a semicolon comment
}

if (char === '(') {
// Start parentheses comment
if (openParens === 0) {
currentComment = '';
} else if (openParens > 0) {
currentComment += char;
}
openParens = Math.min(openParens + 1, Number.MAX_SAFE_INTEGER);
} else if (char === ')') {
// End parentheses comment
openParens = Math.max(0, openParens - 1);
if (openParens === 0) {
comments.push(currentComment.trim());
currentComment = '';
} else if (openParens > 0) {
currentComment += char;
}
} else if (openParens > 0) {
// Inside parentheses comment
currentComment += char;
} else {
// Normal text outside comments
strippedLine += char;
}
}

result = result.trim();
return [result, comments];
};
strippedLine = strippedLine.trim();

return (line) => {
const [strippedLine, comments] = _stripComments(line);
return [strippedLine, comments];
};
})();
return [strippedLine, comments];
};

const stripWhitespace = (line) => {
// Remove whitespace characters
const re = new RegExp(/\s+/g);
return line.replace(re, '');
};
// Returns the stripped line without comments.
const stripComments = (line) => stripCommentsEx(line)[0];

// Removes whitespace characters.
const stripWhitespace = (line) => {
const re = new RegExp(/\s+/g);
return line.replace(re, '');
};

// @param {string} line The G-code line
const parseLine = (() => {
// eslint-disable-next-line no-useless-escape
const re = /(%.*)|({.*)|((?:\$\$)|(?:\$[a-zA-Z0-9#]*))|([a-zA-Z][0-9\+\-\.]+)|(\*[0-9]+)/igm;

Expand All @@ -159,7 +158,7 @@ const parseLine = (() => {
let ln; // Line number
let cs; // Checksum
const originalLine = line;
const [strippedLine, comments] = stripComments(line);
const [strippedLine, comments] = stripCommentsEx(line);
const compactLine = stripWhitespace(strippedLine);

if (lineMode === 'compact') {
Expand Down Expand Up @@ -418,5 +417,6 @@ export {
parseLine,
parseStream,
parseString,
parseStringSync
parseStringSync,
stripComments,
};
Loading