From a0fcb918bffc940cb1ceab4202f94bdbe57bd645 Mon Sep 17 00:00:00 2001 From: notaphplover Date: Mon, 30 Dec 2024 00:48:05 +0100 Subject: [PATCH] chore(inversify-code-examples): update example generator Update script to parse and handle exclude from example comments --- .../tools/inversify-code-examples/README.md | 5 +- .../inversify-code-examples/package.json | 2 +- .../src/scripts/generateExamples.mts | 120 +++++++++++------- 3 files changed, 80 insertions(+), 47 deletions(-) diff --git a/packages/docs/tools/inversify-code-examples/README.md b/packages/docs/tools/inversify-code-examples/README.md index 4f65e147..e32109c2 100644 --- a/packages/docs/tools/inversify-code-examples/README.md +++ b/packages/docs/tools/inversify-code-examples/README.md @@ -5,8 +5,9 @@ Inversify docs code examples. ## Adding code examples 1. Just create your code example in the `src/examples` folder with an integration test to verify the expected behavior. -2. User a `// Begin-example` comment to set the begining of the example. -3. Use a `// End-example` comment to set the end of the example. +2. Use a `// Begin-example` comment to set the begining of the example. +3. Use a `// Exclude-from-example` comment to exclude a sentence from the example. +4. Use a `// End-example` comment to set the end of the example. 2. Run the `build` script. 3. Your code example will be available in the `generated/examples` folder. diff --git a/packages/docs/tools/inversify-code-examples/package.json b/packages/docs/tools/inversify-code-examples/package.json index 4105e638..61ecb61b 100644 --- a/packages/docs/tools/inversify-code-examples/package.json +++ b/packages/docs/tools/inversify-code-examples/package.json @@ -50,7 +50,7 @@ "scripts": { "build": "pnpm run build:cjs && pnpm run generate:examples", "build:cjs": "tsc --build tsconfig.cjs.json && pnpm exec foundation-ts-package-cjs ./lib/cjs", - "build:clean": "rimraf lib", + "build:clean": "rimraf generated lib", "format": "prettier --write ./src/**/*.ts", "generate:examples": "node ./lib/cjs/scripts/generateExamples.mjs", "lint": "eslint ./src", diff --git a/packages/docs/tools/inversify-code-examples/src/scripts/generateExamples.mts b/packages/docs/tools/inversify-code-examples/src/scripts/generateExamples.mts index faaa6d46..6cfa804d 100644 --- a/packages/docs/tools/inversify-code-examples/src/scripts/generateExamples.mts +++ b/packages/docs/tools/inversify-code-examples/src/scripts/generateExamples.mts @@ -11,23 +11,27 @@ const EXAMPLES_GLOB_PATTERN: string = `${SRC_FOLDER}/examples/*.ts`; const TEST_EXAMPLES_GLOB_PATTERN: string = `${SRC_FOLDER}/examples/*.spec.ts`; enum RelevanCommentKind { - beginExample, - endExample, + begin, + end, + exclude, } interface RelevanCommentPositions { - [RelevanCommentKind.beginExample]: [ts.CommentRange, ts.Node][]; - [RelevanCommentKind.endExample]: [ts.CommentRange, ts.Node][]; + [RelevanCommentKind.begin]: [ts.CommentRange, ts.Node][]; + [RelevanCommentKind.end]: [ts.CommentRange, ts.Node][]; + [RelevanCommentKind.exclude]: [ts.CommentRange, ts.Node][]; } const BEGIN_EXAMPLE_COMMENT: string = '// Begin-example'; const END_EXAMPLE_COMMENT: string = '// End-example'; +const EXCLUDE_FROM_EXAMPLE_COMMENT: string = '// Exclude-from-example'; const commentToRelevantCommentKindMap: { [key: string]: RelevanCommentKind; } = { - [BEGIN_EXAMPLE_COMMENT]: RelevanCommentKind.beginExample, - [END_EXAMPLE_COMMENT]: RelevanCommentKind.endExample, + [BEGIN_EXAMPLE_COMMENT]: RelevanCommentKind.begin, + [END_EXAMPLE_COMMENT]: RelevanCommentKind.end, + [EXCLUDE_FROM_EXAMPLE_COMMENT]: RelevanCommentKind.exclude, }; function findRelevantCommentPositions( @@ -35,8 +39,9 @@ function findRelevantCommentPositions( sourceFileNode: ts.Node, ): RelevanCommentPositions { const positions: RelevanCommentPositions = { - [RelevanCommentKind.beginExample]: [], - [RelevanCommentKind.endExample]: [], + [RelevanCommentKind.begin]: [], + [RelevanCommentKind.end]: [], + [RelevanCommentKind.exclude]: [], }; visitRelevantCommentPositions(fileContent, sourceFileNode, positions); @@ -76,38 +81,6 @@ function visitRelevantCommentPositions( } } -function getCodeExampleBegining( - sourceFile: ts.SourceFile, - positions: RelevanCommentPositions, -): number { - const [firstBeginExamplePosition]: [ts.CommentRange, ts.Node][] = - positions[RelevanCommentKind.beginExample]; - - if (firstBeginExamplePosition === undefined) { - return 0; - } - - const [, node] = firstBeginExamplePosition; - - return node.getStart(sourceFile); -} - -function getCodeExampleEnd( - sourceFile: ts.SourceFile, - positions: RelevanCommentPositions, -): number { - const lastEndExamplePosition: [ts.CommentRange, ts.Node] | undefined = - positions[RelevanCommentKind.endExample].at(-1); - - if (lastEndExamplePosition === undefined) { - return sourceFile.end; - } - - const [comment] = lastEndExamplePosition; - - return comment.pos; -} - async function getExamplePaths(): Promise { return glob(EXAMPLES_GLOB_PATTERN, { ignore: TEST_EXAMPLES_GLOB_PATTERN }); } @@ -126,10 +99,7 @@ async function generateExampleFromSourceCode( const relevantCommentPositions: RelevanCommentPositions = findRelevantCommentPositions(fileContent, sourceFile); - return fileContent.slice( - getCodeExampleBegining(sourceFile, relevantCommentPositions), - getCodeExampleEnd(sourceFile, relevantCommentPositions), - ); + return transformSourceFile(sourceFile, relevantCommentPositions); } async function writeSourceCodeExample( @@ -153,11 +123,73 @@ async function run(): Promise { const codeExamplePaths: string[] = await getExamplePaths(); for (const codeExamplePath of codeExamplePaths) { + console.log(`Generating code example at ${codeExamplePath}...`); + await writeSourceCodeExample( codeExamplePath, await generateExampleFromSourceCode(codeExamplePath), ); + + console.log('Code example generated successfully'); } } await run(); + +function getExcludeRanges( + sourceFile: ts.SourceFile, + positions: RelevanCommentPositions, +): [number, number][] { + const [firstBeginOfExamplePosition]: [ts.CommentRange, ts.Node][] = + positions[RelevanCommentKind.begin]; + + const lastEndOfExamplePosition: [ts.CommentRange, ts.Node] | undefined = + positions[RelevanCommentKind.end].at(-1); + + const excludedRanges: [number, number][] = []; + + if (firstBeginOfExamplePosition !== undefined) { + const [commentNode] = firstBeginOfExamplePosition; + + excludedRanges.push([0, commentNode.end]); + } + + for (const [, node] of positions[RelevanCommentKind.exclude]) { + excludedRanges.push([node.pos, node.end]); + } + + if (lastEndOfExamplePosition !== undefined) { + const [, node] = lastEndOfExamplePosition; + + excludedRanges.push([node.pos, sourceFile.end]); + } + + return excludedRanges; +} + +function transformSourceFile( + sourceFile: ts.SourceFile, + positions: RelevanCommentPositions, +): string { + const excludedRanges: [number, number][] = getExcludeRanges( + sourceFile, + positions, + ); + + let transformedSourceCode: string = ''; + let currentIndex: number = 0; + + for (const [min, max] of excludedRanges) { + while (currentIndex <= max) { + if (currentIndex < min) { + transformedSourceCode += sourceFile.text[currentIndex]; + } + + ++currentIndex; + } + } + + transformedSourceCode += sourceFile.text.slice(currentIndex); + + return transformedSourceCode; +}