From 5741498a23425d71579ee22b55cda77a26636f8e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 23:43:23 +0000 Subject: [PATCH 1/3] Initial plan From 90c4ebf5a476e76d6185e68edb7e7099312629fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 23:48:35 +0000 Subject: [PATCH 2/3] Support default values for non-optional properties (issue #186) Co-authored-by: syavorsky <455779+syavorsky@users.noreply.github.com> Agent-Logs-Url: https://github.com/syavorsky/comment-parser/sessions/aac64fd7-b4bb-4fe7-be23-0d98267555b2 --- src/parser/tokenizers/name.ts | 26 ++++++ tests/e2e/issue-186.spec.js | 30 +++++++ tests/unit/spec-name-tokenizer.spec.ts | 108 +++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 tests/e2e/issue-186.spec.js diff --git a/src/parser/tokenizers/name.ts b/src/parser/tokenizers/name.ts index fabf02de..779e9fbb 100644 --- a/src/parser/tokenizers/name.ts +++ b/src/parser/tokenizers/name.ts @@ -111,6 +111,32 @@ export default function nameTokenizer(): Tokenizer { }); return spec; } + } else { + const eqIndex = name.indexOf('='); + if (eqIndex !== -1) { + defaultValue = name.slice(eqIndex + 1); + name = name.slice(0, eqIndex); + + if (name === '') { + spec.problems.push({ + code: 'spec:name:empty-name', + message: 'empty name', + line: spec.source[0].number, + critical: true, + }); + return spec; + } + + if (defaultValue === '') { + spec.problems.push({ + code: 'spec:name:empty-default', + message: 'empty default value', + line: spec.source[0].number, + critical: true, + }); + return spec; + } + } } spec.optional = optional; diff --git a/tests/e2e/issue-186.spec.js b/tests/e2e/issue-186.spec.js new file mode 100644 index 00000000..f455598a --- /dev/null +++ b/tests/e2e/issue-186.spec.js @@ -0,0 +1,30 @@ +const { parse } = require('../../lib/index.cjs'); + +test('non-optional property with default value', () => { + const parsed = parse(` + /** + * Some annoying set of bitmasks or something. + * + * @property {number} BITMASK_VALUE_A=16 - blah blah + * @property {number} BITMASK_VALUE_B=32 - the other thing + */`); + + expect(parsed[0].tags).toMatchObject([ + { + tag: 'property', + type: 'number', + name: 'BITMASK_VALUE_A', + optional: false, + default: '16', + description: '- blah blah', + }, + { + tag: 'property', + type: 'number', + name: 'BITMASK_VALUE_B', + optional: false, + default: '32', + description: '- the other thing', + }, + ]); +}); diff --git a/tests/unit/spec-name-tokenizer.spec.ts b/tests/unit/spec-name-tokenizer.spec.ts index cffcb236..d315040e 100644 --- a/tests/unit/spec-name-tokenizer.spec.ts +++ b/tests/unit/spec-name-tokenizer.spec.ts @@ -620,6 +620,114 @@ test('empty', () => { ); }); +test('non-optional with default', () => { + expect( + tokenize( + seedSpec({ + source: [ + { + number: 1, + source: '...', + tokens: seedTokens({ + description: 'param=value param description', + }), + }, + ], + }) + ) + ).toEqual( + seedSpec({ + name: 'param', + optional: false, + default: 'value', + source: [ + { + number: 1, + source: '...', + tokens: seedTokens({ + name: 'param=value', + postName: ' ', + description: 'param description', + }), + }, + ], + }) + ); +}); + +test('non-optional with numeric default', () => { + expect( + tokenize( + seedSpec({ + source: [ + { + number: 1, + source: '...', + tokens: seedTokens({ + description: 'BITMASK_VALUE_A=16 blah blah', + }), + }, + ], + }) + ) + ).toEqual( + seedSpec({ + name: 'BITMASK_VALUE_A', + optional: false, + default: '16', + source: [ + { + number: 1, + source: '...', + tokens: seedTokens({ + name: 'BITMASK_VALUE_A=16', + postName: ' ', + description: 'blah blah', + }), + }, + ], + }) + ); +}); + +test('non-optional with empty default', () => { + expect( + tokenize( + seedSpec({ + source: [ + { + number: 1, + source: '...', + tokens: seedTokens({ + description: 'param= param description', + }), + }, + ], + }) + ) + ).toEqual( + seedSpec({ + problems: [ + { + code: 'spec:name:empty-default', + line: 1, + critical: true, + message: 'empty default value', + }, + ], + source: [ + { + number: 1, + source: '...', + tokens: seedTokens({ + description: 'param= param description', + }), + }, + ], + }) + ); +}); + test('default value syntax', () => { expect( tokenize( From 786bf5ffd5768564d0ba0326dac8cf880999f62d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 19:14:13 +0000 Subject: [PATCH 3/3] Align non-optional default validation with optional path (trim, invalid-default check, test) Agent-Logs-Url: https://github.com/syavorsky/comment-parser/sessions/5da727bd-4934-4851-b3ad-eea43977b1a2 Co-authored-by: syavorsky <455779+syavorsky@users.noreply.github.com> --- src/parser/tokenizers/name.ts | 19 ++++++++++--- tests/unit/spec-name-tokenizer.spec.ts | 38 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/parser/tokenizers/name.ts b/src/parser/tokenizers/name.ts index 779e9fbb..d2300909 100644 --- a/src/parser/tokenizers/name.ts +++ b/src/parser/tokenizers/name.ts @@ -112,10 +112,10 @@ export default function nameTokenizer(): Tokenizer { return spec; } } else { - const eqIndex = name.indexOf('='); - if (eqIndex !== -1) { - defaultValue = name.slice(eqIndex + 1); - name = name.slice(0, eqIndex); + const parts = name.split('='); + if (parts.length > 1) { + name = parts[0].trim(); + defaultValue = parts.slice(1).join('=').trim(); if (name === '') { spec.problems.push({ @@ -136,6 +136,17 @@ export default function nameTokenizer(): Tokenizer { }); return spec; } + + // has "=" and is not a string, except for "=>" + if (!isQuoted(defaultValue) && /=(?!>)/.test(defaultValue)) { + spec.problems.push({ + code: 'spec:name:invalid-default', + message: 'invalid default value syntax', + line: spec.source[0].number, + critical: true, + }); + return spec; + } } } diff --git a/tests/unit/spec-name-tokenizer.spec.ts b/tests/unit/spec-name-tokenizer.spec.ts index d315040e..0da879d2 100644 --- a/tests/unit/spec-name-tokenizer.spec.ts +++ b/tests/unit/spec-name-tokenizer.spec.ts @@ -728,6 +728,44 @@ test('non-optional with empty default', () => { ); }); +test('non-optional with invalid default syntax', () => { + expect( + tokenize( + seedSpec({ + source: [ + { + number: 1, + source: '...', + tokens: seedTokens({ + description: 'param=value=value param description', + }), + }, + ], + }) + ) + ).toEqual( + seedSpec({ + problems: [ + { + code: 'spec:name:invalid-default', + line: 1, + critical: true, + message: 'invalid default value syntax', + }, + ], + source: [ + { + number: 1, + source: '...', + tokens: seedTokens({ + description: 'param=value=value param description', + }), + }, + ], + }) + ); +}); + test('default value syntax', () => { expect( tokenize(