Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,52 @@ export const config = {
};
```

## Type Safety with Generated Types

Shnippet automatically generates TypeScript types for your snippet names. After running the extractor, you'll find a `gen-types` directory in your snippets folder containing type definitions.

### Using Generated Types

Import the `SnippetName` type in your TypeScript files:

```typescript
import type { SnippetName } from '../snippets/gen-types';

// Now you get type safety and autocomplete for snippet names
const snippetName: SnippetName = 'example1'; // ✅ Type-safe
const invalidName: SnippetName = 'not-a-snippet'; // ❌ Type error
```

The generated types ensure you're using valid snippet names throughout your codebase.

### Using with SnippetManager

The generated types work seamlessly with `snippetManager`:

```typescript
import { snippetManager } from 'shnippet';
import type { SnippetName } from '../snippets/gen-types';

// Type-safe snippet fetching
const result = await snippetManager.getSnippet('example1' as SnippetName);

// Type-safe in React components
function CodeExample() {
const [snippet, setSnippet] = useState<SnippetResult | null>(null);

useEffect(() => {
async function loadSnippet() {
// TypeScript ensures you're using a valid snippet name
const result = await snippetManager.getSnippet('example1' as SnippetName);
setSnippet(result);
}
loadSnippet();
}, []);

// ... rest of component
}
```

## Adding Snippets to Your Test Files

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.
Expand Down Expand Up @@ -272,6 +318,7 @@ snippetManager.updateConfig({
baseUrl: 'http://your-snippet-server.com/snippets',

// Languages to support
// Note: The first language in this array will be used as the defaultLanguage
supportedLanguages: ['python', 'kotlin', 'typescript'],

// Default imports for each language
Expand All @@ -284,3 +331,18 @@ snippetManager.updateConfig({
```

The snippet manager will cache the results, making subsequent fetches instant.

### Default Language Behavior

The `defaultLanguage` in the returned `SnippetResult` is always set to the first language in the `supportedLanguages` array. This means:

1. The order of languages in your `supportedLanguages` configuration determines which language is used as the default
2. This default is set regardless of whether the snippet exists in that language
3. You can control the default language by reordering the `supportedLanguages` array

For example, if you want Kotlin to be the default language, put it first in the array:
```typescript
snippetManager.updateConfig({
supportedLanguages: ['kotlin', 'python', 'typescript'] // Kotlin will be the default
});
```
2 changes: 2 additions & 0 deletions example/shnippet.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ export const config = {
prependEnd: ":prepend-end:",
},
outputDirectoryStructure: "byLanguage",
baseUrl: "http://localhost:3000",
supportedLanguages: ["python", "kotlin", "javascript"]
};
46 changes: 0 additions & 46 deletions example/src/App.jsx

This file was deleted.

109 changes: 109 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React, { useState, useEffect } from 'react';
import { snippetManager } from 'shnippet';
import { config } from '../shnippet.config';
import type { SnippetResult } from 'shnippet';
import type { SnippetName } from '../snippets/gen-types';


// Update the snippetManager with our config
snippetManager.updateConfig(config);

function App() {
const [snippetResult, setSnippetResult] = useState<SnippetResult | null>(null);
const [selectedLanguage, setSelectedLanguage] = useState<string>('');
const [error, setError] = useState<string>('');

useEffect(() => {
async function loadSnippet() {
try {
// Try to load a test snippet
const result = await snippetManager.getSnippet('example1' as SnippetName);

setSnippetResult(result);
// Set initial language to the default language
setSelectedLanguage(result.defaultLanguage);
} catch (err) {
setError(err.message);
}
}
loadSnippet();
}, []);

if (error) {
return (
<div style={{ padding: '20px' }}>
<h1>Shnippet Test</h1>
<div style={{ color: 'red' }}>Error: {error}</div>
</div>
);
}

if (!snippetResult) {
return (
<div style={{ padding: '20px' }}>
<h1>Shnippet Test</h1>
<div>Loading...</div>
</div>
);
}

return (
<div style={{ padding: '20px' }}>
<h1>Shnippet Test</h1>

{/* Language Tabs */}
<div style={{ marginBottom: '20px' }}>
{snippetResult.languages.map((language) => (
<button
key={language}
onClick={() => setSelectedLanguage(language)}
style={{
padding: '8px 16px',
marginRight: '8px',
border: 'none',
background: selectedLanguage === language ? '#007bff' : '#f0f0f0',
color: selectedLanguage === language ? 'white' : 'black',
cursor: 'pointer',
borderRadius: '4px',
}}
>
{language}
</button>
))}
</div>

{/* Code Display */}
{snippetResult.imports?.[selectedLanguage] && (
<div>
<h3>Imports:</h3>
<pre
style={{
background: '#f5f5f5',
padding: '15px',
borderRadius: '4px',
whiteSpace: 'pre-wrap',
}}
>
{snippetResult.imports[selectedLanguage].join('\n')}
</pre>
</div>
)}

<div style={{ marginBottom: '20px' }}>
<h3>Code:</h3>
<pre
style={{
background: '#f5f5f5',
padding: '15px',
borderRadius: '4px',
whiteSpace: 'pre-wrap',
}}
>
{snippetResult.content[selectedLanguage]}
</pre>
</div>
</div>
);
}

export default App;
17 changes: 5 additions & 12 deletions package/build.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
import { build } from 'esbuild';
import { rimraf } from 'rimraf';

// Clean dist directory
await rimraf('dist');

// Build Node.js bundle
// Build Node.js CLI bundle
await build({
entryPoints: ['src/index.ts', 'src/bin/cli.ts'],
entryPoints: ['src/bin/cli.ts'],
bundle: true,
platform: 'node',
target: 'node18',
format: 'esm',
outdir: 'dist',
outExtension: { '.js': '.js' },
external: ['rimraf'],
banner: {
js: '#!/usr/bin/env node\n',
},
outdir: 'dist/bin',
banner: { js: '#!/usr/bin/env node\n' },
sourcemap: true,
minify: false,
});
Expand All @@ -33,4 +25,5 @@ await build({
sourcemap: true,
minify: true,
globalName: 'Shnippet',
external: ['fs', 'path', 'events', 'stream', 'string_decoder'],
});
Loading