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', 'state.json', 'svg-sprite.manifest.json', ]) 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}$/, ) const state = JSON.parse(fs.readFileSync(path.join(rootDir, '.svg-sprite', 'state.json'), 'utf8')) assert.deepEqual(state.owner, { mode: 'standalone', contractVersion: 2 }) }) 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.deepEqual(generatedFiles(rootDir), [ 'icon-data.d.ts', 'icon-data.js', 'index.d.ts', 'index.js', 'sprite.svg', 'state.json', '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') assert.match(entry, /sprite\.svg\?no-inline/) assert.match(entry, /export const iconsSpriteUrl = spriteUrl/) assert.match(entry, /export function getIconsIconHref\(icon\)/) assert.match(declarations, /getIconsIconHref\(icon: IconsIconName\): string/) assert.match(manifest, /"mode": "standalone@vite"/) assert.match(manifest, /export const spriteManifest = createSpriteManifest\(spriteUrl\)/) assert.doesNotMatch(entry, /react|jsx|\.css/) }) 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') assert.match(entry, /new URL\('\.\/sprite\.svg', import\.meta\.url\)\.href/) assert.match(entry, /export function getIconsIconHref\(icon\)/) assert.match(manifest, /"mode": "standalone@webpack"/) assert.match(manifest, /new URL\('\.\/sprite\.svg', import\.meta\.url\)\.href/) assert.doesNotMatch(entry, /react|jsx|\.css/) }) test('switching standalone modes removes obsolete managed files', async () => { const rootDir = fixture() const options = { name: 'icons', generatedNotice: false } await generateSprite(rootDir, { ...options, mode: 'standalone@vite' }) fs.writeFileSync(path.join(rootDir, '.svg-sprite', 'user.txt'), 'keep') await generateSprite(rootDir, { ...options, mode: 'standalone' }) assert.deepEqual(generatedFiles(rootDir), [ 'sprite.svg', 'state.json', 'svg-sprite.manifest.json', 'user.txt', ]) assert.equal(fs.readFileSync(path.join(rootDir, '.svg-sprite', 'user.txt'), 'utf8'), 'keep') await generateSprite(rootDir, { ...options, mode: 'standalone@webpack' }) 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')), true) })