|
| 1 | +# Shnippet |
| 2 | + |
| 3 | +Shnippet is a versatile code snippet extraction tool designed to help you manage and organize code snippets from your source files, particularly your test suites. It allows you to use your written tests as source code for content that gets surfaced in documentation. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +- **Leverage Test Suites**: Use your existing tests as the source for documentation snippets. |
| 8 | +- **Customizable Snippet Extraction**: Define custom tags to mark the start and end of code snippets. |
| 9 | +- **Multi-Language Support**: Works with various programming languages by specifying file extensions. |
| 10 | +- **Flexible Output Structure**: Choose how your snippets are organized in the output directory. |
| 11 | +- **Prepend Blocks**: Include import statements or other code that should precede your snippets. |
| 12 | +- **CLI Integration**: Use the command-line interface for easy integration into your build process. |
| 13 | + |
| 14 | +## Installation |
| 15 | + |
| 16 | +Install Shnippet as a dev dependency in your project: |
| 17 | + |
| 18 | +``` |
| 19 | +npm install --save-dev shnippet |
| 20 | +``` |
| 21 | + |
| 22 | +Or with pnpm: |
| 23 | + |
| 24 | +``` |
| 25 | +pnpm add -D shnippet |
| 26 | +``` |
| 27 | + |
| 28 | +## Getting Started |
| 29 | + |
| 30 | +### Configuration |
| 31 | + |
| 32 | +Create a `shnippet.config.ts` file in the root directory of your project: |
| 33 | + |
| 34 | +```typescript |
| 35 | +export const config = { |
| 36 | + rootDirectory: "./src", // Directory containing source files |
| 37 | + snippetOutputDirectory: "./snippets", // Directory to store extracted snippets |
| 38 | + fileExtensions: [".js", ".ts", ".kt", ".gradle", ".xml", ".bash", ".swift"], // Supported file types |
| 39 | + exclude: ["excludeThisSnippet"], // Snippets to exclude |
| 40 | + snippetTags: { |
| 41 | + start: ":snippet-start:", |
| 42 | + end: ":snippet-end:", |
| 43 | + prependStart: ":prepend-start:", |
| 44 | + prependEnd: ":prepend-end:", |
| 45 | + }, |
| 46 | + outputDirectoryStructure: "byLanguage", // How snippets are organized |
| 47 | + version: "1.0.0", // Versioning for output directories |
| 48 | +}; |
| 49 | +``` |
| 50 | + |
| 51 | +## Adding Snippets to Your Test Files |
| 52 | + |
| 53 | +Mark the code you want to extract using the custom snippet tags defined in your configuration. By placing these tags in your test suites, you can directly extract code examples from your tests. |
| 54 | + |
| 55 | +### Example in a TypeScript test file: |
| 56 | + |
| 57 | +```typescript |
| 58 | +// :snippet-start: exampleTestSnippet |
| 59 | +test("should greet the user", () => { |
| 60 | + const name = "Alice"; |
| 61 | + const greeting = greet(name); |
| 62 | + expect(greeting).toBe("Hello, Alice!"); |
| 63 | +}); |
| 64 | +// :snippet-end: |
| 65 | +``` |
| 66 | + |
| 67 | +### Using Prepend Blocks |
| 68 | + |
| 69 | +Include code that should be prepended to your snippets, such as import statements. |
| 70 | + |
| 71 | +```typescript |
| 72 | +// :prepend-start: exampleTestSnippet |
| 73 | +import { greet } from "../src/greet"; |
| 74 | +// :prepend-end: |
| 75 | +``` |
| 76 | + |
| 77 | +## Extracting Snippets |
| 78 | + |
| 79 | +Use the Shnippet CLI to extract snippets based on your configuration. |
| 80 | + |
| 81 | +### Running the Extractor |
| 82 | + |
| 83 | +Add a script to your `package.json`: |
| 84 | + |
| 85 | +```json |
| 86 | +"scripts": { |
| 87 | + "shnippet": "shnippet --config ./shnippet.config.ts" |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +Then run: |
| 92 | + |
| 93 | +``` |
| 94 | +npm run shnippet |
| 95 | +``` |
| 96 | + |
| 97 | +Or with pnpm: |
| 98 | + |
| 99 | +``` |
| 100 | +pnpm shnippet |
| 101 | +``` |
| 102 | + |
| 103 | +## CLI Options |
| 104 | + |
| 105 | +Shnippet provides several command-line options for additional control. |
| 106 | + |
| 107 | +### Clear Output Directory |
| 108 | + |
| 109 | +Remove all extracted snippets. |
| 110 | + |
| 111 | +``` |
| 112 | +npm run shnippet -- clear |
| 113 | +``` |
| 114 | + |
| 115 | +### Specify Output Structure |
| 116 | + |
| 117 | +Choose how snippets are organized (`flat`, `match`, `organized`, `byLanguage`). |
| 118 | + |
| 119 | +``` |
| 120 | +npm run shnippet -- --structure byLanguage |
| 121 | +``` |
| 122 | + |
| 123 | +## Error Handling |
| 124 | + |
| 125 | +Shnippet provides clear error messages for common issues when extracting snippets. Here are the main error cases and how to handle them: |
| 126 | + |
| 127 | +### Missing End Tag |
| 128 | + |
| 129 | +If a snippet is missing its end tag, Shnippet will throw an error with a descriptive message: |
| 130 | + |
| 131 | +``` |
| 132 | +Error: Missing end tag for snippet 'example' in file example.js |
| 133 | +``` |
| 134 | + |
| 135 | +### Missing Snippet Name |
| 136 | + |
| 137 | +If a snippet start tag is missing its name, Shnippet will throw an error: |
| 138 | + |
| 139 | +``` |
| 140 | +Error: Missing snippet name in file example.js |
| 141 | +``` |
| 142 | + |
| 143 | +### Example of Proper Snippet Format |
| 144 | + |
| 145 | +Here's an example of the correct format for snippets: |
| 146 | + |
| 147 | +```javascript |
| 148 | +// Correct format |
| 149 | +//:snippet-start: hello-world |
| 150 | +function hello() { |
| 151 | + console.log("Hello, world!"); |
| 152 | +} |
| 153 | +//:snippet-end: |
| 154 | + |
| 155 | +// Incorrect formats that will cause errors: |
| 156 | +//:snippet-start: // Missing name |
| 157 | +function hello() { |
| 158 | + console.log("Hello, world!"); |
| 159 | +} |
| 160 | +//:snippet-end: |
| 161 | + |
| 162 | +//:snippet-start: hello-world |
| 163 | +function hello() { |
| 164 | + console.log("Hello, world!"); |
| 165 | +} // Missing end tag |
| 166 | +``` |
| 167 | + |
| 168 | +## Configuration Options |
| 169 | + |
| 170 | +- **`rootDirectory`**: Root directory containing the source files (e.g., your test suites). |
| 171 | +- **`snippetOutputDirectory`**: Directory where snippets will be saved. |
| 172 | +- **`fileExtensions`**: Array of file extensions to process. |
| 173 | +- **`exclude`**: Array of snippet names to exclude from extraction. |
| 174 | +- **`snippetTags`**: Custom tags to identify snippet boundaries. |
| 175 | + - `start`: Tag indicating the start of a snippet. |
| 176 | + - `end`: Tag indicating the end of a snippet. |
| 177 | + - `prependStart`: Tag indicating the start of a prepend block. |
| 178 | + - `prependEnd`: Tag indicating the end of a prepend block. |
| 179 | +- **`outputDirectoryStructure`**: Determines how snippets are organized in the output directory. |
| 180 | +- **`version`**: Version identifier used in the output directory path. |
| 181 | + |
| 182 | +## Output Directory Structures |
| 183 | + |
| 184 | +- **`flat`**: All snippets are placed in a single directory. |
| 185 | +- **`match`**: Snippets mirror the directory structure of the source files. |
| 186 | +- **`organized`**: Snippets are organized based on custom logic. |
| 187 | +- **`byLanguage`**: Snippets are grouped by programming language (default). |
| 188 | + |
| 189 | +## Examples |
| 190 | + |
| 191 | +### Extracting and Using a Test Snippet |
| 192 | + |
| 193 | +**Test File (`tests/greet.test.ts`):** |
| 194 | + |
| 195 | +```typescript |
| 196 | +// :prepend-start: greetTest |
| 197 | +import { greet } from "../src/greet"; |
| 198 | +// :prepend-end: |
| 199 | + |
| 200 | +// :snippet-start: greetTest |
| 201 | +test("should greet the user", () => { |
| 202 | + const name = "Bob"; |
| 203 | + const greeting = greet(name); |
| 204 | + expect(greeting).toBe("Hello, Bob!"); |
| 205 | +}); |
| 206 | +// :snippet-end: |
| 207 | +``` |
| 208 | + |
| 209 | +**Extract Snippets:** |
| 210 | + |
| 211 | +``` |
| 212 | +npm run shnippet |
| 213 | +``` |
| 214 | + |
| 215 | +**Use Extracted Snippet in Documentation:** |
| 216 | + |
| 217 | +The extracted snippets will be available in your `snippets` directory, organized by language. For example: |
| 218 | + |
| 219 | +``` |
| 220 | +snippets/ |
| 221 | + 1.0.0/ |
| 222 | + typescript/ |
| 223 | + greetTest.snippet.txt |
| 224 | +``` |
| 225 | + |
| 226 | +## Troubleshooting |
| 227 | + |
| 228 | +### Unexpected Virtual Store Location Error |
| 229 | + |
| 230 | +If you encounter an error regarding the virtual store location, reinstall your dependencies: |
| 231 | + |
| 232 | +``` |
| 233 | +pnpm install |
| 234 | +``` |
| 235 | + |
| 236 | +Alternatively, specify the virtual store directory in your `.npmrc` file: |
| 237 | + |
| 238 | +``` |
| 239 | +virtual-store-dir = "node_modules/.pnpm" |
| 240 | +``` |
| 241 | + |
| 242 | +## Displaying Snippets with SnippetManager |
| 243 | + |
| 244 | +The snippet manager is a utility for fetching and displaying code snippets in your frontend application. It handles caching, language-specific formatting, and imports. |
| 245 | + |
| 246 | +### Basic Usage |
| 247 | + |
| 248 | +```typescript |
| 249 | +import { snippetManager } from '@shnippet/core'; |
| 250 | + |
| 251 | +// Get a snippet in a specific language |
| 252 | +const pythonCode = await snippetManager.getSnippet('my-snippet', 'python'); |
| 253 | + |
| 254 | +// Get display info (available languages and imports) |
| 255 | +const info = snippetManager.getSnippetDisplayInfo('my-snippet'); |
| 256 | +// Returns: { |
| 257 | +// languages: ['python', 'kotlin'], |
| 258 | +// defaultLanguage: 'python', |
| 259 | +// imports: { python: ['from typing import Any'] } |
| 260 | +// } |
| 261 | +``` |
| 262 | + |
| 263 | +### Configuration |
| 264 | + |
| 265 | +**Note** You probably will never need to configure snippetManager, it's just available for edge-cases. |
| 266 | + |
| 267 | +You can configure the snippet manager to match your needs. This allows you to overwrite your original snippet config settings. |
| 268 | + |
| 269 | +```typescript |
| 270 | +snippetManager.updateConfig({ |
| 271 | + // Base URL for fetching snippets |
| 272 | + baseUrl: 'http://your-snippet-server.com/snippets', |
| 273 | + |
| 274 | + // Languages to support |
| 275 | + supportedLanguages: ['python', 'kotlin', 'typescript'], |
| 276 | + |
| 277 | + // Default imports for each language |
| 278 | + defaultImports: { |
| 279 | + python: ['from typing import Any'], |
| 280 | + kotlin: ['import java.util.*'], |
| 281 | + typescript: ['import { useState } from "react"'] |
| 282 | + } |
| 283 | +}); |
| 284 | +``` |
| 285 | + |
| 286 | +The snippet manager will cache the results, making subsequent fetches instant. |
0 commit comments