import assert from 'node:assert/strict' import fs from 'node:fs' import os from 'node:os' import path from 'node:path' import test from 'node:test' import { generateSprite, isSpriteMode } from '../dist/index.js' const CHECK_SVG = '' const UNSAFE_SVG = '' function fixture() { const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), 'svg-sprites-standalone-')) const iconsDir = path.join(rootDir, 'icons') fs.mkdirSync(iconsDir) fs.writeFileSync(path.join(iconsDir, 'check.svg'), CHECK_SVG) fs.writeFileSync(path.join(iconsDir, 'folder open.svg'), UNSAFE_SVG) return rootDir } function generatedFiles(rootDir) { return fs.readdirSync(path.join(rootDir, '.svg-sprite')).sort() } test('recognizes all standalone exact modes', () => { assert.equal(isSpriteMode('standalone'), true) assert.equal(isSpriteMode('standalone@vite'), true) assert.equal(isSpriteMode('standalone@webpack'), true) assert.equal(isSpriteMode('standalone@rollup'), false) }) test('standalone generates an asset and deployment-neutral JSON manifest', async () => { const rootDir = fixture() const result = await generateSprite(rootDir, { mode: 'standalone', name: 'app-icons', generatedNotice: false, }) assert.equal(result.mode, 'standalone') assert.equal(result.target, 'static') assert.equal(result.iconCount, 2) assert.equal(result.spritePath, path.join(rootDir, '.svg-sprite', 'sprite.svg')) assert.equal(result.manifestPath, path.join(rootDir, '.svg-sprite', 'svg-sprite.manifest.json')) assert.deepEqual(generatedFiles(rootDir), [ 'sprite.svg', 'svg-sprite.manifest.json', ]) assert.equal(fs.existsSync(path.join(rootDir, '.gitignore')), false) const source = fs.readFileSync(result.spritePath, 'utf8') assert.match(source, /@generated by @gromlab\/svg-sprites/) assert.match(source, /id="check"/) const manifest = JSON.parse(fs.readFileSync(result.manifestPath, 'utf8')) assert.equal(manifest.name, 'app-icons') assert.equal(manifest.mode, 'standalone') assert.equal(manifest.target, 'static') assert.match(manifest.generated, /@generated by @gromlab\/svg-sprites/) assert.equal('spriteUrl' in manifest, false) assert.equal('componentName' in manifest, false) assert.equal(manifest.icons.find(({ name }) => name === 'check').id, 'check') assert.match( manifest.icons.find(({ name }) => name === 'folder open').id, /^icon-[a-f0-9]{16}$/, ) }) test('standalone preserves a user-owned .gitignore', async () => { const rootDir = fixture() const gitignorePath = path.join(rootDir, '.gitignore') fs.writeFileSync(gitignorePath, '/public/cache/\n') await generateSprite(rootDir, { mode: 'standalone', name: 'app-icons', generatedNotice: false, }) assert.equal(fs.readFileSync(gitignorePath, 'utf8'), '/public/cache/\n') }) test('standalone Vite generates a typed facade and resolved manifest', async () => { const rootDir = fixture() const result = await generateSprite(rootDir, { mode: 'standalone@vite', name: 'icons', generatedNotice: false, }) assert.equal(result.target, 'vite') assert.equal(fs.existsSync(path.join(rootDir, '.gitignore')), true) assert.deepEqual(generatedFiles(rootDir), [ 'icon-data.d.ts', 'icon-data.js', 'index.d.ts', 'index.js', 'sprite.svg', 'svg-sprite.manifest.d.ts', 'svg-sprite.manifest.js', ]) const entry = fs.readFileSync(path.join(rootDir, '.svg-sprite', 'index.js'), 'utf8') const declarations = fs.readFileSync(path.join(rootDir, '.svg-sprite', 'index.d.ts'), 'utf8') const manifest = fs.readFileSync(result.manifestPath, 'utf8') const manifestDeclarations = fs.readFileSync(path.join(rootDir, '.svg-sprite', 'svg-sprite.manifest.d.ts'), 'utf8') assert.match(entry, /sprite\.svg\?no-inline/) assert.match(entry, /export const iconsSpriteUrl = spriteUrl/) assert.match(entry, /export const iconsIconTagName = "icons-icon"/) assert.match(entry, /export function getIconsIconHref\(icon\)/) assert.match(entry, /export function defineIconsIconElement\(\)/) assert.match(entry, /class IconsIconElement extends globalThis\.HTMLElement/) assert.match(entry, /this\.attachShadow\(\{ mode: 'open' \}\)/) assert.match(entry, /"folder open": "0 0 16 16"/) assert.match(declarations, /getIconsIconHref\(icon: IconsIconName\): string/) assert.match(declarations, /export interface IconsIconElement extends HTMLElement/) assert.match(declarations, /icon: IconsIconName \| null/) assert.match(declarations, /"icons-icon": IconsIconElement/) assert.match(manifest, /"mode": "standalone@vite"/) assert.match(manifest, /export const spriteManifest = createSpriteManifest\(spriteUrl\)/) assert.match(manifestDeclarations, /export type SpriteManifestData/) assert.match(manifestDeclarations, /mode: 'standalone@vite'/) assert.doesNotMatch(manifestDeclarations, /from '@gromlab\/svg-sprites'/) assert.doesNotMatch(entry, /react|jsx|\.css|\blit\b/i) }) test('standalone Webpack generates a typed facade and resolved manifest', async () => { const rootDir = fixture() const result = await generateSprite(rootDir, { mode: 'standalone@webpack', name: 'icons', generatedNotice: false, }) assert.equal(result.target, 'webpack') const entry = fs.readFileSync(path.join(rootDir, '.svg-sprite', 'index.js'), 'utf8') const manifest = fs.readFileSync(result.manifestPath, 'utf8') const manifestDeclarations = fs.readFileSync(path.join(rootDir, '.svg-sprite', 'svg-sprite.manifest.d.ts'), 'utf8') assert.match(entry, /new URL\('\.\/sprite\.svg', import\.meta\.url\)\.href/) assert.match(entry, /export function getIconsIconHref\(icon\)/) assert.match(entry, /export const iconsIconTagName = "icons-icon"/) assert.match(entry, /export function defineIconsIconElement\(\)/) assert.match(manifest, /"mode": "standalone@webpack"/) assert.match(manifest, /new URL\('\.\/sprite\.svg', import\.meta\.url\)\.href/) assert.match(manifestDeclarations, /export type SpriteManifestData/) assert.match(manifestDeclarations, /mode: 'standalone@webpack'/) assert.doesNotMatch(manifestDeclarations, /from '@gromlab\/svg-sprites'/) assert.doesNotMatch(entry, /react|jsx|\.css|\blit\b/i) }) test('switching standalone modes replaces the generated directory', async () => { const rootDir = fixture() const options = { name: 'icons', generatedNotice: false } await generateSprite(rootDir, { ...options, mode: 'standalone@vite' }) assert.equal(fs.existsSync(path.join(rootDir, '.gitignore')), true) fs.writeFileSync(path.join(rootDir, '.svg-sprite', 'user.txt'), 'keep') await generateSprite(rootDir, { ...options, mode: 'standalone' }) assert.deepEqual(generatedFiles(rootDir), [ 'sprite.svg', 'svg-sprite.manifest.json', ]) assert.equal(fs.existsSync(path.join(rootDir, '.gitignore')), false) assert.equal(fs.existsSync(path.join(rootDir, '.svg-sprite', 'user.txt')), false) await generateSprite(rootDir, { ...options, mode: 'standalone@webpack' }) assert.equal(fs.existsSync(path.join(rootDir, '.gitignore')), true) assert.equal(fs.existsSync(path.join(rootDir, '.svg-sprite', 'svg-sprite.manifest.json')), false) assert.equal(fs.existsSync(path.join(rootDir, '.svg-sprite', 'index.js')), true) assert.equal(fs.existsSync(path.join(rootDir, '.svg-sprite', 'user.txt')), false) })