diff --git a/src/parser/tokenizers/name.ts b/src/parser/tokenizers/name.ts index fabf02de..d2300909 100644 --- a/src/parser/tokenizers/name.ts +++ b/src/parser/tokenizers/name.ts @@ -111,6 +111,43 @@ export default function nameTokenizer(): Tokenizer { }); return spec; } + } else { + const parts = name.split('='); + if (parts.length > 1) { + name = parts[0].trim(); + defaultValue = parts.slice(1).join('=').trim(); + + 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; + } + + // 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; + } + } } 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..0da879d2 100644 --- a/tests/unit/spec-name-tokenizer.spec.ts +++ b/tests/unit/spec-name-tokenizer.spec.ts @@ -620,6 +620,152 @@ 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('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(