diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/README.md b/lib/node_modules/@stdlib/_tools/doctest/c/extract/README.md new file mode 100644 index 000000000000..a4e2591f0d9f --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/README.md @@ -0,0 +1,142 @@ + + +# C Doctest Extract + +> Extract C doctest example blocks from a source or Markdown file. + + + +
+ +
+ + + + + +
+ +## Usage + +```javascript +var extract = require( '@stdlib/_tools/doctest/c/extract' ); +``` + +#### extract( file\[, mode] ) + +Extracts C example blocks from a file and returns an array of block objects. + + + + + +```javascript +var blocks = extract( '/path/to/file.c', 'src' ); +// returns [ { 'file': '...', 'blockIndex': 0, 'includes': [...], 'body': [...], 'annotations': [...], ... }, ... ] +``` + +The function accepts the following arguments: + +- **file**: `string` absolute path to the file to parse. +- **mode**: `string` extraction mode. Must be either `'src'` (default) or `'markdown'`. + +When `mode` is `'src'`, the function scans for `@example` blocks inside JSDoc-style `/** ... */` comments in C source files. When `mode` is `'markdown'`, the function scans for fenced ` ```c ` code blocks inside `
`, `
`, or `
` sections of Markdown files. + +Each returned block object has the following shape: + +```text +{ + "file": "/path/to/file.c", // absolute path of the source file + "blockIndex": 0, // zero-based index of the block within the file + "includes": [...], // `#include` lines (each: { text, line }) + "staticHelpers": [...], // file-level `static` declarations (each: { text, line }) + "fileScope": [...], // file-scope code outside any function (each: { text, line }) + "body": [...], // executable body lines (each: { text, line }) + "annotations": [...] // `// returns` comment lines (each: { text, line }) +} +``` + +Blocks are skipped when: + +- the file contains a `// stdlib-c-doctest disable-file` directive (all blocks are skipped), or +- the function definition immediately following the block is annotated with `// stdlib-c-doctest disable`, or +- a `` comment precedes the fenced block, or +- the fenced block only contains `#include` lines, looks like a function signature, or contains placeholder ellipsis (`...`). + +
+ + + + + +
+ +## Notes + +- Line numbers in returned objects are **1-indexed** and correspond to actual lines in the source file. +- Contiguous lines within the same category (e.g., consecutive `body` lines) are merged into a single entry whose `text` contains embedded newlines. + +
+ + + + + +
+ +## Examples + + + +```javascript +var join = require( 'path' ).join; +var extract = require( '@stdlib/_tools/doctest/c/extract' ); + +// Extract blocks from a C source file: +var srcFile = join( __dirname, 'test', 'fixtures', 'src', 'test_edge_cases.c' ); +var srcBlocks = extract( srcFile, 'src' ); +console.dir( srcBlocks ); + +// Extract blocks from a Markdown file: +var mdFile = join( __dirname, '..', '..', '..', '..', 'math', 'base', 'special', 'abs', 'README.md' ); +var mdBlocks = extract( mdFile, 'markdown' ); +console.dir( mdBlocks ); +``` + +
+ + + + + + + + + + + + + + diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/benchmark/benchmark.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/benchmark/benchmark.js new file mode 100644 index 000000000000..dc4224e797f1 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/benchmark/benchmark.js @@ -0,0 +1,76 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var join = require( 'path' ).join; +var isArray = require( '@stdlib/assert/is-array' ); +var bench = require( '@stdlib/bench' ); +var format = require( '@stdlib/string/format' ); +var extract = require( './../lib' ); +var pkg = require( './../package.json' ).name; + + +// VARIABLES // + +var FIXTURES_DIR = join( __dirname, '..', 'test', 'fixtures' ); +var SRC_FILE = join( FIXTURES_DIR, 'src', 'test_edge_cases.c' ); +var MD_FILE = join( FIXTURES_DIR, '..', '..', '..', '..', '..', '..', 'math', 'base', 'special', 'abs', 'README.md' ); + + +// MAIN // + +bench( format( '%s::src', pkg ), function benchmark( b ) { + var out; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + out = extract( SRC_FILE, 'src' ); + if ( typeof out !== 'object' ) { + b.fail( 'should return an array' ); + } + } + b.toc(); + if ( !isArray( out ) ) { + b.fail( 'should return an array' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( format( '%s::markdown', pkg ), function benchmark( b ) { + var out; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + out = extract( MD_FILE, 'markdown' ); + if ( typeof out !== 'object' ) { + b.fail( 'should return an array' ); + } + } + b.toc(); + if ( !isArray( out ) ) { + b.fail( 'should return an array' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/docs/types/index.d.ts b/lib/node_modules/@stdlib/_tools/doctest/c/extract/docs/types/index.d.ts new file mode 100644 index 000000000000..67a107aa3b93 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/docs/types/index.d.ts @@ -0,0 +1,95 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +// TypeScript Version: 4.1 + +/* eslint-disable max-lines */ + +/** +* Extracted block line object. +*/ +interface BlockLine { + /** + * Line text. + */ + text: string; + + /** + * Line number. + */ + line: number; +} + +/** +* Extracted block object. +*/ +interface Block { + /** + * File path. + */ + file: string; + + /** + * Block index. + */ + blockIndex: number; + + /** + * Include statements. + */ + includes: Array; + + /** + * Static helper functions. + */ + staticHelpers: Array; + + /** + * File-scope code lines. + */ + fileScope: Array; + + /** + * Block body code lines. + */ + body: Array; + + /** + * Annotations (i.e., `// returns` comments). + */ + annotations: Array; +} + +/** +* Extracts example blocks from a file. +* +* @param file - file path +* @param mode - extraction mode (e.g., `"src"` or `"markdown"`) (default: "src") +* @returns extracted blocks +* +* @example +* var join = require( 'path' ).join; +* +* var fpath = join( __dirname, '..', '..', 'test', 'fixtures', 'src', 'test_edge_cases.c' ); +* var blocks = extract( fpath, 'src' ); +*/ +declare function extract( file: string, mode?: 'src' | 'markdown' ): Array; + +// EXPORTS // + +export = extract; diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/docs/types/test.ts b/lib/node_modules/@stdlib/_tools/doctest/c/extract/docs/types/test.ts new file mode 100644 index 000000000000..299d63874a5f --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/docs/types/test.ts @@ -0,0 +1,60 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* eslint-disable @typescript-eslint/no-unused-expressions */ + +import extract = require( './index' ); + +// TESTS // + +// The function returns an array of blocks... +{ + extract( 'path/to/file.c' ); // $ExpectType Block[] + extract( 'path/to/file.c', 'src' ); // $ExpectType Block[] + extract( 'path/to/file.md', 'markdown' ); // $ExpectType Block[] +} + +// The compiler throws an error if the function is provided a first argument which is not a string... +{ + extract( 123 ); // $ExpectError + extract( true ); // $ExpectError + extract( false ); // $ExpectError + extract( null ); // $ExpectError + extract( undefined ); // $ExpectError + extract( [] ); // $ExpectError + extract( {} ); // $ExpectError + extract( ( x: number ): number => x ); // $ExpectError +} + +// The compiler throws an error if the function is provided a second argument which is not an allowed string... +{ + extract( 'path/to/file.c', 123 ); // $ExpectError + extract( 'path/to/file.c', true ); // $ExpectError + extract( 'path/to/file.c', false ); // $ExpectError + extract( 'path/to/file.c', null ); // $ExpectError + extract( 'path/to/file.c', [] ); // $ExpectError + extract( 'path/to/file.c', {} ); // $ExpectError + extract( 'path/to/file.c', ( x: number ): number => x ); // $ExpectError + extract( 'path/to/file.c', 'invalid_mode' ); // $ExpectError +} + +// The compiler throws an error if the function is provided an unsupported number of arguments... +{ + extract(); // $ExpectError + extract( 'path/to/file.c', 'src', 1 ); // $ExpectError +} diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/examples/index.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/examples/index.js new file mode 100644 index 000000000000..45b03f842d9d --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/examples/index.js @@ -0,0 +1,50 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var join = require( 'path' ).join; +var extract = require( './../lib' ); + + +// VARIABLES // + +var FIXTURES_DIR = join( __dirname, '..', 'test', 'fixtures' ); + + +// MAIN // + +// Extract example blocks from a C source file: +var srcFile = join( FIXTURES_DIR, 'src', 'test_edge_cases.c' ); +var srcBlocks = extract( srcFile, 'src' ); + +console.log( 'Source file — extracted blocks: %d', srcBlocks.length ); +console.dir( srcBlocks, { + 'depth': null +}); + +// Extract example blocks from a Markdown README: +var mdFile = join( FIXTURES_DIR, '..', '..', '..', '..', '..', '..', 'math', 'base', 'special', 'abs', 'README.md' ); +var mdBlocks = extract( mdFile, 'markdown' ); + +console.log( 'Markdown file — extracted blocks: %d', mdBlocks.length ); +console.dir( mdBlocks, { + 'depth': null +}); diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract.js new file mode 100644 index 000000000000..4040a9216e66 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract.js @@ -0,0 +1,60 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var readFileSync = require( '@stdlib/fs/read-file' ).sync; +var extractCSource = require( './extract_c_source.js' ); +var extractMarkdown = require( './extract_markdown.js' ); + + +// MAIN // + +// eslint-disable-next-line stdlib/jsdoc-doctest +/** +* Extracts example blocks from a file. +* +* @param {string} file - file path +* @param {string} [mode="src"] - mode: "src" or "markdown" +* @returns {Array} extracted blocks +* +* @example +* var blocks = extract( '/path/to/file.c', 'src' ); +* // returns [ {...}, ... ] +*/ +function extract( file, mode ) { + var src; + + // eslint-disable-next-line n/no-sync + src = readFileSync( file, 'utf8' ); + if ( src instanceof Error ) { + throw src; + } + + if ( mode === 'markdown' ) { + return extractMarkdown( src, file ); + } + return extractCSource( src, file ); +} + + +// EXPORTS // + +module.exports = extract; diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract_c_source.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract_c_source.js new file mode 100644 index 000000000000..d625f6573626 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract_c_source.js @@ -0,0 +1,100 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var flushBlock = require( './flush_block.js' ); + + +// MAIN // + +/** +* Extracts blocks from source string. +* +* @private +* @param {string} src - source string +* @param {string} file - file path +* @returns {Array} blocks +* +* @example +* var src = '/**\\n* @example\\n* int x = 0;\\n*' + '/'; +* extractCSource( src, '/path/to/file.c' ); +*/ +function extractCSource( src, file ) { + var blockLines; + var inDocBlock; + var cleanLine; + var inExample; + var blocks; + var lines; + var line; + var out; + var i; + + blocks = []; + + if ( /^\s*\/\/\s*stdlib-c-doctest\s+disable-file\b/m.test( src ) ) { + return blocks; + } + + lines = src.split( '\n' ); + inDocBlock = false; + inExample = false; + blockLines = []; + + for ( i = 0; i < lines.length; i++ ) { + line = lines[ i ]; + + if ( inDocBlock ) { + if ( /^\s*\*\//.test( line ) ) { + if ( inExample ) { + flushBlock( blockLines, lines, i, blocks, file ); + } + inDocBlock = false; + inExample = false; + } else if ( /^\s*\*\s*@example/.test( line ) ) { + if ( inExample ) { + flushBlock( blockLines, lines, i, blocks, file ); + } + inExample = true; + blockLines = []; + } else if ( inExample ) { + // Replace leading `* ` with ` ` to preserve column offset + cleanLine = line.replace( /^(\s*)\*( ?)/, '$1 ' ); + out = { + 'text': cleanLine, + 'line': i + 1 + }; + blockLines.push( out ); + } + } else if ( /^\s*\/\*\*/.test( line ) ) { + inDocBlock = true; + inExample = false; + blockLines = []; + } + } + + return blocks; +} + + +// EXPORTS // + +module.exports = extractCSource; diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract_markdown.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract_markdown.js new file mode 100644 index 000000000000..20c56e3b0d18 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract_markdown.js @@ -0,0 +1,162 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var processBlock = require( './process_block.js' ); + + +// MAIN // + +/** +* Extracts example blocks from a Markdown file. +* +* @private +* @param {string} src - source string +* @param {string} file - file path +* @returns {Array} blocks +* +* @example +* var src = '```c\\nint x = 0;\\n```'; +* extractMarkdown( src, '/path/to/file.md' ); +*/ +function extractMarkdown( src, file ) { + var isPureEllipsisComment; + var inExamplesSection; + var isFuncSignature; + var hasPlaceholders; + var isOnlyIncludes; + var ellipsisInCode; + var inUsageSection; + var blockLines; + var inCSection; + var skipBlock; + var inFenced; + var codePart; + var blocks; + var isTodo; + var lines; + var line; + var text; + var i; + var j; + var k; + + blocks = []; + lines = src.split( '\n' ); + inFenced = false; + inCSection = false; + inExamplesSection = false; + inUsageSection = false; + blockLines = []; + skipBlock = false; + + for ( i = 0; i < lines.length; i++ ) { + line = lines[ i ]; + + if ( /
/.test( line ) ) { + inCSection = true; + } + if ( /
/.test( line ) ) { + inExamplesSection = true; + } + if ( /
/.test( line ) ) { + inUsageSection = true; + } + if ( /<\/section>/.test( line ) ) { + if ( inExamplesSection ) { + inExamplesSection = false; + } else if ( inUsageSection ) { + inUsageSection = false; + } else if ( inCSection ) { + inCSection = false; + } + } + + if ( inFenced ) { + if ( /^```$/.test( line ) ) { + inFenced = false; + + // Additional heuristic skips based on block content: + isOnlyIncludes = true; + isFuncSignature = ( + blockLines.length === 1 && + /;\s*$/.test( blockLines[ 0 ].text ) && + /\(.*\)/.test( blockLines[ 0 ].text ) && + !/[=]/.test( blockLines[ 0 ].text ) + ); + isTodo = false; + hasPlaceholders = false; + + for ( j = 0; j < blockLines.length; j++ ) { + text = blockLines[ j ].text; + if ( !/^\s*#include\b/.test( text ) && !/^\s*$/.test( text ) ) { + isOnlyIncludes = false; + } + if ( /^\s*(?:\/\/)?\s*TODO\b/i.test( text ) ) { + isTodo = true; + } + codePart = text.replace( /\/\/.*$/, '' ); + ellipsisInCode = /\.\.\./.test( codePart ) || /…/.test( codePart ); + isPureEllipsisComment = /\/\/\s*\.{3}\s*$/.test( text ) && !/\S/.test( codePart ); + if ( ellipsisInCode || isPureEllipsisComment ) { + hasPlaceholders = true; + } + } + + if ( isOnlyIncludes || isFuncSignature || hasPlaceholders || isTodo ) { + skipBlock = true; + } + + if ( !skipBlock ) { + blocks.push(processBlock( blockLines, file, blocks.length )); + } + } else { + blockLines.push({ + 'text': line, + 'line': i + 1 + }); + } + } else if ( /^```c\b/.test( line ) ) { + skipBlock = false; + if ( i > 0 ) { + k = i - 1; + while ( k >= 0 && /^\s*$/.test( lines[ k ] ) ) { + k -= 1; + } + if ( k >= 0 && //.test( lines[ k ] ) ) { + skipBlock = true; + } + } + if ( !inCSection && !inExamplesSection && !inUsageSection ) { + skipBlock = true; + } + inFenced = true; + blockLines = []; + } + } + + return blocks; +} + + +// EXPORTS // + +module.exports = extractMarkdown; diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract_static_helpers.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract_static_helpers.js new file mode 100644 index 000000000000..d009d3b75fd9 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/extract_static_helpers.js @@ -0,0 +1,90 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MAIN // + +/** +* Scans the file to extract all depth-0 `static` helpers (variables, functions, arrays) and top-level `#define` macros. +* +* @private +* @param {Array} lines - source lines +* @returns {Array} array of line objects for the static helpers +* +* @example +* var lines = [ +* 'static void foo() {', +* ' return;', +* '}' +* ]; +* var out = extractStaticHelpers( lines ); +* // returns [ { 'text': 'static void foo() {', 'line': 1 }, ... ] +*/ +function extractStaticHelpers( lines ) { + var braceDepth; + var inDefine; + var inStatic; + var line; + var out; + var i; + + out = []; + inStatic = false; + inDefine = false; + braceDepth = 0; + + for ( i = 0; i < lines.length; i++ ) { + line = lines[ i ]; + + if ( !inStatic && !inDefine ) { + if ( /^static\b/.test( line ) ) { + inStatic = true; + braceDepth = 0; + } else if ( /^#define\b/.test( line ) ) { + inDefine = true; + } + } + if ( inStatic ) { + out.push({ + 'text': line, + 'line': i + 1 + }); + + braceDepth += ( line.match( /\{/g ) || [] ).length; + braceDepth -= ( line.match( /\}/g ) || [] ).length; + if ( braceDepth === 0 && ( /;/.test( line ) || /\}/.test( line ) ) ) { + inStatic = false; + } + } else if ( inDefine ) { + out.push({ + 'text': line, + 'line': i + 1 + }); + if ( !/\\\s*$/.test( line ) ) { + inDefine = false; + } + } + } + return out; +} + + +// EXPORTS // + +module.exports = extractStaticHelpers; diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/flush_block.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/flush_block.js new file mode 100644 index 000000000000..317b6ef9eb9d --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/flush_block.js @@ -0,0 +1,79 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var extractStaticHelpers = require( './extract_static_helpers.js' ); +var groupContiguousLines = require( './group_contiguous_lines.js' ); +var processBlock = require( './process_block.js' ); + + +// MAIN // + +/** +* Flushes a collected example block by checking skip conditions and, if not skipped, processing it into a structured object, extracting any required static helpers, and adding it to the output. +* +* @private +* @param {Array} blockLines - collected lines of the current block +* @param {Array} lines - all source lines +* @param {number} startIdx - line index from which to begin scanning for a skip marker +* @param {Array} blocks - output array to push processed block into +* @param {string} file - file path +* +* @example +* flushBlock( blockLines, lines, i, blocks, '/path/to/file.c' ); +*/ +function flushBlock( blockLines, lines, startIdx, blocks, file ) { + var staticHelpers; + var scanLine; + var blockObj; + var k; + var j; + + // Find skip rules and stop if a function is reached... + for ( j = startIdx; j < lines.length; j++ ) { + scanLine = lines[ j ]; + if ( /\/\/\s*stdlib-c-doctest\s+disable\b/.test( scanLine ) ) { + return; + } + if ( /\{/.test( scanLine ) ) { + break; + } + } + + // Check for ellipsis placeholder in example content... + for ( k = 0; k < blockLines.length; k++ ) { + if ( /\.\.\./.test( blockLines[ k ].text ) ) { + return; + } + } + + blockObj = processBlock( blockLines, file, blocks.length ); + staticHelpers = extractStaticHelpers( lines ); + if ( staticHelpers.length > 0 ) { + blockObj.staticHelpers = groupContiguousLines( staticHelpers ); + } + blocks.push( blockObj ); +} + + +// EXPORTS // + +module.exports = flushBlock; diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/group_contiguous_lines.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/group_contiguous_lines.js new file mode 100644 index 000000000000..4ecf9b25eaa4 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/group_contiguous_lines.js @@ -0,0 +1,72 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MAIN // + +/** +* Groups contiguous lines into single text blocks. +* +* @private +* @param {Array} lines - array of line objects +* @returns {Array} grouped lines +* +* @example +* var lines = [ +* { 'text': 'a', 'line': 1 }, +* { 'text': 'b', 'line': 2 } +* ]; +* var out = groupContiguousLines( lines ); +* // returns [ { 'text': 'a\\nb', 'line': 1 } ] +*/ +function groupContiguousLines( lines ) { + var curr; + var out; + var i; + + if ( lines.length === 0 ) { + return []; + } + + out = []; + curr = { + 'text': lines[ 0 ].text, + 'line': lines[ 0 ].line + }; + + for ( i = 1; i < lines.length; i++ ) { + if ( lines[ i ].line === lines[ i - 1 ].line + 1 ) { + curr.text += '\n' + lines[ i ].text; + } else { + out.push( curr ); + curr = { + 'text': lines[ i ].text, + 'line': lines[ i ].line + }; + } + } + out.push( curr ); + + return out; +} + + +// EXPORTS // + +module.exports = groupContiguousLines; diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/index.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/index.js new file mode 100644 index 000000000000..f6602a8c2a1f --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/index.js @@ -0,0 +1,39 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +/** +* Parse C examples for doctests. +* +* @module @stdlib/_tools/doctest/c/extract +* +* @example +* var extract = require( '@stdlib/_tools/doctest/c/extract' ); +* +* var blocks = extract( '/path/to/file.c', 'src' ); +*/ + +// MODULES // + +var extract = require( './extract.js' ); + + +// EXPORTS // + +module.exports = extract; diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/process_block.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/process_block.js new file mode 100644 index 000000000000..8def1fde8238 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/lib/process_block.js @@ -0,0 +1,117 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var groupContiguousLines = require( './group_contiguous_lines.js' ); + + +// MAIN // + +/** +* Processes lines of an extracted block. +* +* @private +* @param {Array} blockLines - array of line objects +* @param {string} file - file path +* @param {number} blockIndex - index of the block in the file +* @returns {Object} processed block +* +* @example +* var lines = [ { 'text': 'int x = 0;', 'line': 1 } ]; +* processBlock( lines, '/path/to/file.c', 0 ); +*/ +function processBlock( blockLines, file, blockIndex ) { + var topLevelBlockIsFunc; + var annotations; + var closeBraces; + var braceDepth; + var openBraces; + var fileScope; + var lastFnEnd; + var includes; + var lineObj; + var body; + var text; + var i; + + includes = []; + fileScope = []; + body = []; + annotations = []; + lastFnEnd = -1; + braceDepth = 0; + topLevelBlockIsFunc = false; + + // Find line number of the last function or pre-function definition closing brace... + + // Note: this assumes all structs and helper functions are grouped together at the top of the snippet + for ( i = 0; i < blockLines.length; i++ ) { + text = blockLines[ i ].text; + openBraces = ( text.match( /\{/g ) || [] ).length; + closeBraces = ( text.match( /\}/g ) || [] ).length; + + if ( braceDepth === 0 && openBraces > 0 ) { + if ( /^\s*(?:if|else|for|while|switch|do)\b/.test( text ) || /[=]\s*\{/.test( text ) ) { + topLevelBlockIsFunc = false; + } else { + topLevelBlockIsFunc = true; + } + } + + braceDepth += openBraces; + braceDepth -= closeBraces; + + if ( topLevelBlockIsFunc && braceDepth === 0 ) { + lastFnEnd = blockLines[ i ].line; + topLevelBlockIsFunc = false; + } + } + + // Categorize by position... + for ( i = 0; i < blockLines.length; i++ ) { + lineObj = blockLines[ i ]; + + if ( /^\s*#include\b/.test( lineObj.text ) ) { + includes.push( lineObj ); + } else if ( lineObj.line <= lastFnEnd ) { + fileScope.push( lineObj ); + } else if ( /^\s*\/\/\s*returns\b/.test( lineObj.text ) ) { + annotations.push( lineObj ); + } else { + body.push( lineObj ); + } + } + + return { + 'file': file, + 'blockIndex': blockIndex, + 'includes': groupContiguousLines( includes ), + 'staticHelpers': [], + 'fileScope': groupContiguousLines( fileScope ), + 'body': groupContiguousLines( body ), + 'annotations': annotations + }; +} + + +// EXPORTS // + +module.exports = processBlock; diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/package.json b/lib/node_modules/@stdlib/_tools/doctest/c/extract/package.json new file mode 100644 index 000000000000..6a45c481929b --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/package.json @@ -0,0 +1,64 @@ +{ + "name": "@stdlib/_tools/doctest/c/extract", + "version": "0.0.0", + "description": "Parse C examples for doctests", + "license": "Apache-2.0", + "author": { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + }, + "contributors": [ + { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + } + ], + "main": "lib/index.js", + "directories": { + "benchmark": "./benchmark", + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "scripts": {}, + "homepage": "https://github.com/stdlib-js/stdlib", + "repository": { + "type": "git", + "url": "git://github.com/stdlib-js/stdlib.git" + }, + "bugs": { + "url": "https://github.com/stdlib-js/stdlib/issues" + }, + "dependencies": {}, + "devDependencies": { + "@stdlib/fs/exists": "^0.0.x", + "@stdlib/fs/read-dir": "^0.0.x", + "@stdlib/fs/read-file": "^0.0.x" + }, + "engines": { + "node": ">=0.10.0", + "npm": ">2.7.0" + }, + "os": [ + "aix", + "darwin", + "freebsd", + "linux", + "macos", + "openbsd", + "sunos", + "win32", + "windows" + ], + "keywords": [ + "stdlib", + "tools", + "doctest", + "c", + "extract", + "parse", + "example" + ] +} diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/blas_base_caxpy_readme.json b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/blas_base_caxpy_readme.json new file mode 100644 index 000000000000..ce2fdfcff2db --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/blas_base_caxpy_readme.json @@ -0,0 +1,59 @@ +[ + { + "file": "/blas/base/caxpy/README.md", + "blockIndex": 0, + "includes": [ + { + "text": "#include \"stdlib/complex/float32/ctor.h\"", + "line": 213 + } + ], + "staticHelpers": [], + "fileScope": [], + "body": [ + { + "text": "\nfloat X[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };\nfloat Y[] = { -1.0f, -2.0f, -3.0f, -4.0f, -5.0f, -6.0f, -7.0f, -8.0f };\nconst stdlib_complex64_t alpha = stdlib_complex64( 2.0f, 2.0f );\n\nc_caxpy( 4, alpha, (void *)X, 1, (void *)Y, 1 );", + "line": 214 + } + ], + "annotations": [] + }, + { + "file": "/blas/base/caxpy/README.md", + "blockIndex": 1, + "includes": [ + { + "text": "#include \"stdlib/complex/float32/ctor.h\"", + "line": 240 + } + ], + "staticHelpers": [], + "fileScope": [], + "body": [ + { + "text": "\nfloat X[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };\nfloat Y[] = { -1.0f, -2.0f, -3.0f, -4.0f, -5.0f, -6.0f, -7.0f, -8.0f };\nconst stdlib_complex64_t alpha = stdlib_complex64( 2.0f, 2.0f );\n\nc_caxpy_ndarray( 4, alpha, (void *)X, 1, 0, (void *)Y, 1, 0 );", + "line": 241 + } + ], + "annotations": [] + }, + { + "file": "/blas/base/caxpy/README.md", + "blockIndex": 2, + "includes": [ + { + "text": "#include \"stdlib/blas/base/caxpy.h\"\n#include \"stdlib/complex/float32/ctor.h\"\n#include ", + "line": 283 + } + ], + "staticHelpers": [], + "fileScope": [ + { + "text": "\nint main( void ) {\n // Create strided arrays of interleaved real and imaginary components...\n float X[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };\n float Y[] = { -1.0f, -2.0f, -3.0f, -4.0f, -5.0f, -6.0f, -7.0f, -8.0f };\n\n // Create a complex scalar:\n const stdlib_complex64_t alpha = stdlib_complex64( 2.0f, 2.0f );\n\n // Specify the number of elements:\n const int N = 4;\n\n // Specify strides...\n const int strideX = 1;\n const int strideY = 1;\n\n // Scale values from `X` by `alpha` and adds the result to `Y`:\n c_caxpy( N, alpha, (void *)X, strideX, (void *)Y, strideY );\n\n // Print the result:\n for ( int i = 0; i < N; i++ ) {\n printf( \"Y[ %i ] = %f + %fj\\n\", i, Y[ i*2 ], Y[ (i*2)+1 ] );\n }\n\n // Scales values from `X` by `alpha` and adds the result to `Y` using alternative indexing semantics:\n c_caxpy_ndarray( N, alpha, (void *)X, -strideX, 3, (void *)Y, -strideY, 3 );\n\n // Print the result:\n for ( int i = 0; i < N; i++ ) {\n printf( \"Y[ %i ] = %f + %fj\\n\", i, Y[ i*2 ], Y[ (i*2)+1 ] );\n }\n}", + "line": 286 + } + ], + "body": [], + "annotations": [] + } +] diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/math_base_assert.json b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/math_base_assert.json new file mode 100644 index 000000000000..b899bd1d4c80 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/math_base_assert.json @@ -0,0 +1,34 @@ +[ + { + "file": "/math/base/assert/is-probability/src/main.c", + "blockIndex": 0, + "includes": [ + { + "text": " #include ", + "line": 29 + } + ], + "staticHelpers": [], + "fileScope": [], + "body": [ + { + "text": " \n bool out = stdlib_base_is_probability( 0.5 );", + "line": 30 + }, + { + "text": " \n out = stdlib_base_is_probability( 1.5 );", + "line": 33 + } + ], + "annotations": [ + { + "text": " // returns true", + "line": 32 + }, + { + "text": " // returns false", + "line": 35 + } + ] + } +] diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/math_base_special_exp2f.json b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/math_base_special_exp2f.json new file mode 100644 index 000000000000..e35bbbe89e5b --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/math_base_special_exp2f.json @@ -0,0 +1,62 @@ +[ + { + "file": "/math/base/special/exp2f/src/main.c", + "blockIndex": 0, + "includes": [], + "staticHelpers": [ + { + "text": "#define TBLSIZE 16", + "line": 59 + }, + { + "text": "#define TBLBITS 4", + "line": 62 + }, + { + "text": "static const double TBL[ TBLSIZE ] = {\n\t0.7071067811865476, // 0x1.6a09e667f3bcdp-1\n\t0.7384130729697497, // 0x1.7a11473eb0187p-1\n\t0.7711054127039704, // 0x1.8ace5422aa0dbp-1\n\t0.8052451659746271, // 0x1.9c49182a3f090p-1\n\t0.8408964152537145, // 0x1.ae89f995ad3adp-1\n\t0.8781260801866497, // 0x1.c199bdd85529cp-1\n\t0.9170040432046712, // 0x1.d5818dcfba487p-1\n\t0.9576032806985737, // 0x1.ea4afa2a490dap-1\n\t1.0, // 0x1.0000000000000p+0\n\t1.0442737824274138, // 0x1.0b5586cf9890fp+0\n\t1.0905077326652577, // 0x1.172b83c7d517bp+0\n\t1.1387886347566916, // 0x1.2387a6e756238p+0\n\t1.189207115002721, // 0x1.306fe0a31b715p+0\n\t1.241857812073484, // 0x1.3dea64c123422p+0\n\t1.2968395546510096, // 0x1.4bfdad5362a27p+0\n\t1.3542555469368927 // 0x1.5ab07dd485429p+0\n};", + "line": 65 + }, + { + "text": "static const float REDUX = 786432.0f;", + "line": 85 + }, + { + "text": "static const float OVERFLOW_THRESHOLD = 128.0f;", + "line": 88 + }, + { + "text": "static const float UNDERFLOW_THRESHOLD = -150.0f;", + "line": 91 + }, + { + "text": "static const float NEARZERO = 1.0f / ( 1 << 25 );", + "line": 94 + }, + { + "text": "static const uint32_t ONE_HIGH_WORD = 0x3ff00000;", + "line": 97 + }, + { + "text": "static double polyval_p12( const double x ) {\n\treturn 0.6931471824645996 + (x * 0.24022650718688965);\n}", + "line": 113 + }, + { + "text": "static double polyval_p34( const double x ) {\n\treturn 0.055505409836769104 + (x * 0.009618354961276054);\n}", + "line": 133 + } + ], + "fileScope": [], + "body": [ + { + "text": " float out = stdlib_base_exp2f( 3.0f );", + "line": 178 + } + ], + "annotations": [ + { + "text": " // returns 8.0f", + "line": 179 + } + ] + } +] diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/ndarray_base_count_falsy_readme.json b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/ndarray_base_count_falsy_readme.json new file mode 100644 index 000000000000..945f3e1ddbcd --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/ndarray_base_count_falsy_readme.json @@ -0,0 +1,21 @@ +[ + { + "file": "/ndarray/base/count-falsy/README.md", + "blockIndex": 0, + "includes": [ + { + "text": "#include \"stdlib/ndarray/base/count_falsy.h\"\n#include \"stdlib/ndarray/dtypes.h\"\n#include \"stdlib/ndarray/index_modes.h\"\n#include \"stdlib/ndarray/orders.h\"\n#include \"stdlib/ndarray/ctor.h\"\n#include \n#include \n#include \n#include ", + "line": 2124 + } + ], + "staticHelpers": [], + "fileScope": [ + { + "text": "\nstatic void print_ndarray_contents( const struct ndarray *x ) {\n int64_t i;\n int32_t v;\n int8_t s;\n\n for ( i = 0; i < stdlib_ndarray_length( x ); i++ ) {\n s = stdlib_ndarray_iget_int32( x, i, &v );\n if ( s != 0 ) {\n fprintf( stderr, \"Unable to resolve data element.\\n\" );\n exit( EXIT_FAILURE );\n }\n fprintf( stdout, \"data[%\"PRId64\"] = %d\\n\", i, v );\n }\n}\n\nint main( void ) {\n // Define the ndarray data types:\n enum STDLIB_NDARRAY_DTYPE xdtype = STDLIB_NDARRAY_UINT8;\n enum STDLIB_NDARRAY_DTYPE ydtype = STDLIB_NDARRAY_INT32;\n\n // Create underlying byte arrays:\n uint8_t xbuf[] = { 1, 2, 3, 4, 5, 6, 7, 8 };\n uint8_t ybuf[] = { 0, 0, 0, 0 };\n\n // Define the number of input array dimensions:\n int64_t ndims = 3;\n\n // Define the array shapes:\n int64_t shx[] = { 2, 2, 2 };\n int64_t *shy = NULL;\n\n // Define the strides:\n int64_t sx[] = { 4, 2, 1 };\n int64_t sy[] = { 0 };\n\n // Define the offsets:\n int64_t ox = 0;\n int64_t oy = 0;\n\n // Define the array order:\n enum STDLIB_NDARRAY_ORDER order = STDLIB_NDARRAY_ROW_MAJOR;\n\n // Specify the index mode:\n enum STDLIB_NDARRAY_INDEX_MODE imode = STDLIB_NDARRAY_INDEX_ERROR;\n\n // Specify the subscript index modes:\n int8_t submodes[] = { imode };\n int64_t nsubmodes = 1;\n\n // Create an input ndarray:\n struct ndarray *x = stdlib_ndarray_allocate( xdtype, xbuf, ndims, shx, sx, ox, order, imode, nsubmodes, submodes );\n if ( x == NULL ) {\n fprintf( stderr, \"Error allocating memory.\\n\" );\n exit( EXIT_FAILURE );\n }\n\n // Create an output ndarray:\n struct ndarray *y = stdlib_ndarray_allocate( ydtype, ybuf, 0, shy, sy, oy, order, imode, nsubmodes, submodes );\n if ( y == NULL ) {\n fprintf( stderr, \"Error allocating memory.\\n\" );\n exit( EXIT_FAILURE );\n }\n\n // Define an array containing the ndarrays:\n struct ndarray *arrays[] = { x, y };\n\n // Perform operation:\n int8_t status = stdlib_ndarray_count_falsy_b_i( arrays, NULL );\n if ( status != 0 ) {\n fprintf( stderr, \"Error during computation.\\n\" );\n exit( EXIT_FAILURE );\n }\n\n // Print the results:\n print_ndarray_contents( y );\n fprintf( stdout, \"\\n\" );\n\n // Free allocated memory:\n stdlib_ndarray_free( x );\n stdlib_ndarray_free( y );\n}", + "line": 2133 + } + ], + "body": [], + "annotations": [] + } +] diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/ndarray_base_ind.json b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/ndarray_base_ind.json new file mode 100644 index 000000000000..f012ae956808 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/ndarray_base_ind.json @@ -0,0 +1,110 @@ +[ + { + "file": "/ndarray/base/ind/src/main.c", + "blockIndex": 0, + "includes": [ + { + "text": " #include \"stdlib/ndarray/index_modes.h\"\n #include \"stdlib/ndarray/base/ind.h\"", + "line": 39 + } + ], + "staticHelpers": [], + "fileScope": [], + "body": [ + { + "text": " \n int64_t idx = stdlib_ndarray_ind( 10, 8, STDLIB_NDARRAY_INDEX_CLAMP );", + "line": 41 + }, + { + "text": " ", + "line": 44 + } + ], + "annotations": [ + { + "text": " // returns 8", + "line": 43 + } + ] + }, + { + "file": "/ndarray/base/ind/src/main.c", + "blockIndex": 1, + "includes": [ + { + "text": " #include \"stdlib/ndarray/index_modes.h\"\n #include \"stdlib/ndarray/base/ind.h\"", + "line": 46 + } + ], + "staticHelpers": [], + "fileScope": [], + "body": [ + { + "text": " \n int64_t idx = stdlib_ndarray_ind( 13, 10, STDLIB_NDARRAY_INDEX_WRAP );", + "line": 48 + }, + { + "text": " ", + "line": 51 + } + ], + "annotations": [ + { + "text": " // returns 2", + "line": 50 + } + ] + }, + { + "file": "/ndarray/base/ind/src/main.c", + "blockIndex": 2, + "includes": [ + { + "text": " #include \"stdlib/ndarray/index_modes.h\"\n #include \"stdlib/ndarray/base/ind.h\"", + "line": 53 + } + ], + "staticHelpers": [], + "fileScope": [], + "body": [ + { + "text": " \n int64_t idx = stdlib_ndarray_ind( 10, 8, STDLIB_NDARRAY_INDEX_ERROR );", + "line": 55 + }, + { + "text": " ", + "line": 58 + } + ], + "annotations": [ + { + "text": " // returns -1", + "line": 57 + } + ] + }, + { + "file": "/ndarray/base/ind/src/main.c", + "blockIndex": 3, + "includes": [ + { + "text": " #include \"stdlib/ndarray/index_modes.h\"\n #include \"stdlib/ndarray/base/ind.h\"", + "line": 60 + } + ], + "staticHelpers": [], + "fileScope": [], + "body": [ + { + "text": " \n int64_t idx = stdlib_ndarray_ind( -4, 8, STDLIB_NDARRAY_INDEX_NORMALIZE );", + "line": 62 + } + ], + "annotations": [ + { + "text": " // returns 5", + "line": 64 + } + ] + } +] diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/stats_base_dists_arcsine.json b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/stats_base_dists_arcsine.json new file mode 100644 index 000000000000..df5f6bcfe892 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/stats_base_dists_arcsine.json @@ -0,0 +1,21 @@ +[ + { + "file": "/stats/base/dists/arcsine/variance/src/main.c", + "blockIndex": 0, + "includes": [], + "staticHelpers": [], + "fileScope": [], + "body": [ + { + "text": " double y = stdlib_base_dists_arcsine_variance( 0.0, 1.0 );", + "line": 30 + } + ], + "annotations": [ + { + "text": " // returns ~0.125", + "line": 31 + } + ] + } +] diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/strided_base.json b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/strided_base.json new file mode 100644 index 000000000000..901cba302220 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/strided_base.json @@ -0,0 +1,68 @@ +[ + { + "file": "/strided/base/function-object/src/main.c", + "blockIndex": 0, + "includes": [ + { + "text": " #include \"stdlib/strided/base/function_object.h\"\n #include \"stdlib/strided/dtypes.h\"\n #include ", + "line": 43 + } + ], + "staticHelpers": [ + { + "text": "static int64_t stdlib_strided_function_dispatch_types_index_of( const int64_t N, const int64_t M, const int32_t *X, const int64_t strideX1, const int64_t strideX2, const int32_t *Y, const int64_t strideY ) {\n\tint64_t ox;\n\tint64_t oy;\n\tint64_t ix;\n\tint64_t iy;\n\tint64_t i;\n\tint64_t j;\n\n\t// Determine initial starting indices (offsets)...\n\tif ( strideX1 < 0 ) {\n\t\tox = (1-N) * strideX1;\n\t} else {\n\t\tox = 0;\n\t}\n\tif ( strideX2 < 0 ) {\n\t\tox += (1-M) * strideX2;\n\t}\n\tif ( strideY < 0 ) {\n\t\toy = (1-M) * strideY;\n\t} else {\n\t\toy = 0;\n\t}\n\t// Search for the first row which matches `Y`...\n\tix = ox;\n\tfor ( i = 0; i < N; i++ ) {\n\t\tiy = oy;\n\t\tfor ( j = 0; j < M; j++ ) {\n\t\t\tif ( X[ ix+(j*strideX2) ] != Y[ iy ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tiy += strideY;\n\t\t}\n\t\t// If we successfully iterated over all columns, then that means we've found a match...\n\t\tif ( j == M ) {\n\t\t\treturn i;\n\t\t}\n\t\tix += strideX1;\n\t}\n\treturn -1;\n}", + "line": 81 + } + ], + "fileScope": [], + "body": [ + { + "text": " \n // Define a reference array to search:\n int32_t X[] = {\n STDLIB_STRIDED_FLOAT64, STDLIB_STRIDED_FLOAT64, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_FLOAT32, STDLIB_STRIDED_FLOAT32, STDLIB_STRIDED_FLOAT32,\n STDLIB_STRIDED_UINT32, STDLIB_STRIDED_UINT32, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_INT32, STDLIB_STRIDED_INT32, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_UINT16, STDLIB_STRIDED_UINT16, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_INT16, STDLIB_STRIDED_INT16, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_UINT8, STDLIB_STRIDED_UINT8, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_INT8, STDLIB_STRIDED_INT8, STDLIB_STRIDED_FLOAT64\n };\n \n // Define reference array dimensions:\n int64_t N = 8; // rows\n int64_t M = 3; // columns\n \n // Define a search array:\n int32_t Y1[] = {\n STDLIB_STRIDED_FLOAT32, STDLIB_STRIDED_FLOAT32, STDLIB_STRIDED_FLOAT32,\n };\n \n // Find the list of types:\n int64_t r1 = stdlib_strided_function_dispatch_types_index_of( N, M, X, M, 1, Y1, 1 );", + "line": 46 + }, + { + "text": " \n // Define a search array:\n int32_t Y2[] = {\n STDLIB_STRIDED_FLOAT32, STDLIB_STRIDED_FLOAT32, STDLIB_STRIDED_FLOAT64,\n };\n \n // Find the list of types:\n int64_t r2 = stdlib_strided_function_dispatch_types_index_of( N, M, X, M, 1, Y2, 1 );", + "line": 71 + } + ], + "annotations": [ + { + "text": " // returns 1", + "line": 70 + }, + { + "text": " // returns -1", + "line": 79 + } + ] + }, + { + "file": "/strided/base/function-object/src/main.c", + "blockIndex": 1, + "includes": [ + { + "text": " #include \"stdlib/strided/base/function_object.h\"\n #include \"stdlib/strided/base/unary.h\"\n #include \"stdlib/strided/dtypes.h\"\n #include \n #include ", + "line": 139 + } + ], + "staticHelpers": [ + { + "text": "static int64_t stdlib_strided_function_dispatch_types_index_of( const int64_t N, const int64_t M, const int32_t *X, const int64_t strideX1, const int64_t strideX2, const int32_t *Y, const int64_t strideY ) {\n\tint64_t ox;\n\tint64_t oy;\n\tint64_t ix;\n\tint64_t iy;\n\tint64_t i;\n\tint64_t j;\n\n\t// Determine initial starting indices (offsets)...\n\tif ( strideX1 < 0 ) {\n\t\tox = (1-N) * strideX1;\n\t} else {\n\t\tox = 0;\n\t}\n\tif ( strideX2 < 0 ) {\n\t\tox += (1-M) * strideX2;\n\t}\n\tif ( strideY < 0 ) {\n\t\toy = (1-M) * strideY;\n\t} else {\n\t\toy = 0;\n\t}\n\t// Search for the first row which matches `Y`...\n\tix = ox;\n\tfor ( i = 0; i < N; i++ ) {\n\t\tiy = oy;\n\t\tfor ( j = 0; j < M; j++ ) {\n\t\t\tif ( X[ ix+(j*strideX2) ] != Y[ iy ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tiy += strideY;\n\t\t}\n\t\t// If we successfully iterated over all columns, then that means we've found a match...\n\t\tif ( j == M ) {\n\t\t\treturn i;\n\t\t}\n\t\tix += strideX1;\n\t}\n\treturn -1;\n}", + "line": 81 + } + ], + "fileScope": [ + { + "text": " \n // Define the function(s) we want to apply to strided arrays:\n double scale( const double x ) {\n return x * 10.0;\n }", + "line": 144 + } + ], + "body": [ + { + "text": " \n // Define a function name:\n const char name[] = \"unary_strided_array_function\";\n \n // Define a list of strided array functions (in this case, as the function to be applied accepts doubles, we only use strided array functions which handle doubles as function arguments and, for the purposes of this example, we assume that the output strided array is always a double-precision floating-point number array):\n StridedArrayFcn functions[] = {\n stdlib_strided_d_d,\n stdlib_strided_f_f_as_d_d,\n stdlib_strided_u_d_as_d_d,\n stdlib_strided_i_d_as_d_d,\n stdlib_strided_t_d_as_d_d,\n stdlib_strided_k_d_as_d_d,\n stdlib_strided_b_d_as_d_d,\n stdlib_strided_s_d_as_d_d\n };\n \n // Define the **strided array** argument types for each strided array function:\n int32_t types[] = {\n STDLIB_STRIDED_FLOAT64, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_FLOAT32, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_UINT32, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_INT32, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_UINT16, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_INT16, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_UINT8, STDLIB_STRIDED_FLOAT64,\n STDLIB_STRIDED_INT8, STDLIB_STRIDED_FLOAT64\n };\n \n // Define a list of strided array function \"data\" (in this case, callbacks):\n void *data[] = {\n (void *)scale,\n (void *)scale,\n (void *)scale,\n (void *)scale,\n (void *)scale,\n (void *)scale,\n (void *)scale,\n (void *)scale\n };\n \n // Create a new strided function object:\n struct StridedFunctionObject *obj = stdlib_strided_function_allocate( name, 1, 1, functions, 8, types, data );\n if ( obj == NULL ) {\n fprintf( stderr, \"Error allocating memory.\\n\" );\n exit( 1 );\n }\n \n // Free allocated memory:\n stdlib_strided_function_free( obj );", + "line": 149 + } + ], + "annotations": [] + } +] diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/test_disable_file.json b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/test_disable_file.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/test_disable_file.json @@ -0,0 +1 @@ +[] diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/test_edge_cases.json b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/test_edge_cases.json new file mode 100644 index 000000000000..07751b3c822b --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/expected/test_edge_cases.json @@ -0,0 +1,21 @@ +[ + { + "file": "/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/src/test_edge_cases.c", + "blockIndex": 0, + "includes": [], + "staticHelpers": [], + "fileScope": [], + "body": [ + { + "text": " int d = extractedFunction();", + "line": 41 + } + ], + "annotations": [ + { + "text": " // returns 4", + "line": 42 + } + ] + } +] diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/src/test_disable_file.c b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/src/test_disable_file.c new file mode 100644 index 000000000000..9932730f01a5 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/src/test_disable_file.c @@ -0,0 +1,36 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +// stdlib-c-doctest disable-file + +/** +* @example +* int a = 1; +*/ +int myFunction() { + return 1; +} + +/** +* @example +* int b = 2; +*/ +int myFunctio2() { + return 3; +} + diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/src/test_edge_cases.c b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/src/test_edge_cases.c new file mode 100644 index 000000000000..a9410a69a069 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/fixtures/src/test_edge_cases.c @@ -0,0 +1,46 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* @example +* int a = 1; +*/ +// stdlib-c-doctest disable +int myFunction() { + return 1; +} + +/** +* @example +* char *s = "\"escaped quote"; +* char *t = "double \\\" escape"; +* int c = 3; +* // returns 3 +*/ +int validFunction() { // stdlib-c-doctest disable + return 3; +} + +/** +* @example +* int d = extractedFunction(); +* // returns 4 +*/ +int extractedFunction() { + return 4; +} diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/test.extract.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/test.extract.js new file mode 100644 index 000000000000..d2b409693f06 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/test.extract.js @@ -0,0 +1,46 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var path = require( 'path' ); +var tape = require( 'tape' ); +var extract = require( './../lib/extract.js' ); + + +// VARIABLES // + +var fixturesDir = path.join( __dirname, 'fixtures' ); + + +// MAIN // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof extract, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'extract handles missing files gracefully or throws', function test( t ) { + t.throws( function onThrow() { + extract( path.join( fixturesDir, 'non_existent.c' ), 'src' ); + }, /ENOENT/, 'throws on missing file' ); + t.end(); +}); diff --git a/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/test.js b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/test.js new file mode 100644 index 000000000000..cfb5041c83d4 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/doctest/c/extract/test/test.js @@ -0,0 +1,126 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var path = require( 'path' ); +var tape = require( 'tape' ); +var readFileSync = require( '@stdlib/fs/read-file' ).sync; +var extract = require( './../lib' ); + + +// VARIABLES // + +var fixturesDir = path.join( __dirname, 'fixtures', 'expected' ); +var atStdlibRoot = path.resolve( __dirname, '..', '..', '..', '..', '..' ); + + +// FUNCTIONS // + +/** +* Validates that the extracted blocks match the expected output. +* +* @private +* @param {Object} t - tape instance +* @param {string} fixtureName - name of the expected JSON file +* @param {string} absolutePath - absolute path to the source file +* @param {string} mode - extraction mode (`src` or `markdown`) +*/ +function check( t, fixtureName, absolutePath, mode ) { + var expectedStr; + var expected; + var actual; + var i; + + // eslint-disable-next-line n/no-sync + expectedStr = readFileSync( path.join( fixturesDir, fixtureName ), 'utf8' ); + if ( expectedStr instanceof Error ) { + t.fail( 'Unable to read expected file: ' + fixtureName ); + t.end(); + return; + } + expected = JSON.parse( expectedStr ); + + // Injects the absolute path back into expected objects... + for ( i = 0; i < expected.length; i++ ) { + if ( expected[ i ].file ) { + expected[ i ].file = absolutePath; + } + } + + actual = extract( absolutePath, mode ); + + t.deepEqual( JSON.parse( JSON.stringify( actual ) ), expected, 'extracted block matches manually authored expected JSON' ); + t.end(); +} + + +// MAIN // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof extract, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'extracts correctly for blas_base_caxpy_readme.json', function test( t ) { + var fpath = path.join( atStdlibRoot, 'blas', 'base', 'caxpy', 'README.md' ); + check( t, 'blas_base_caxpy_readme.json', fpath, 'markdown' ); +}); + +tape( 'extracts correctly for ndarray_base_count_falsy_readme.json', function test( t ) { + var fpath = path.join( atStdlibRoot, 'ndarray', 'base', 'count-falsy', 'README.md' ); + check( t, 'ndarray_base_count_falsy_readme.json', fpath, 'markdown' ); +}); + +tape( 'extracts correctly for math_base_assert.json', function test( t ) { + var fpath = path.join( atStdlibRoot, 'math', 'base', 'assert', 'is-probability', 'src', 'main.c' ); + check( t, 'math_base_assert.json', fpath, 'src' ); +}); + +tape( 'extracts correctly for stats_base_dists_arcsine.json', function test( t ) { + var fpath = path.join( atStdlibRoot, 'stats', 'base', 'dists', 'arcsine', 'variance', 'src', 'main.c' ); + check( t, 'stats_base_dists_arcsine.json', fpath, 'src' ); +}); + +tape( 'extracts correctly for strided_base.json', function test( t ) { + var fpath = path.join( atStdlibRoot, 'strided', 'base', 'function-object', 'src', 'main.c' ); + check( t, 'strided_base.json', fpath, 'src' ); +}); + +tape( 'extracts correctly for math_base_special_exp2f.json', function test( t ) { + var fpath = path.join( atStdlibRoot, 'math', 'base', 'special', 'exp2f', 'src', 'main.c' ); + check( t, 'math_base_special_exp2f.json', fpath, 'src' ); +}); + +tape( 'extracts correctly for ndarray_base_ind.json', function test( t ) { + var fpath = path.join( atStdlibRoot, 'ndarray', 'base', 'ind', 'src', 'main.c' ); + check( t, 'ndarray_base_ind.json', fpath, 'src' ); +}); + +tape( 'extracts correctly for test_disable_file.json', function test( t ) { + var fpath = path.join( __dirname, 'fixtures', 'src', 'test_disable_file.c' ); + check( t, 'test_disable_file.json', fpath, 'src' ); +}); + +tape( 'extracts correctly for test_edge_cases.json', function test( t ) { + var fpath = path.join( __dirname, 'fixtures', 'src', 'test_edge_cases.c' ); + check( t, 'test_edge_cases.json', fpath, 'src' ); +});