Initial import: open-design source for helix-mind.ai distribution
Some checks failed
ci / Validate workspace (push) Successful in 12m32s
landing-page-ci / Validate landing page (push) Successful in 9m41s
landing-page-deploy / Deploy landing page (push) Failing after 5m23s
github-metrics / Generate repository metrics SVG (push) Failing after 2m6s
refresh-contributors-wall / Refresh contributors wall cache bust (push) Failing after 12s
Some checks failed
ci / Validate workspace (push) Successful in 12m32s
landing-page-ci / Validate landing page (push) Successful in 9m41s
landing-page-deploy / Deploy landing page (push) Failing after 5m23s
github-metrics / Generate repository metrics SVG (push) Failing after 2m6s
refresh-contributors-wall / Refresh contributors wall cache bust (push) Failing after 12s
This repository contains the open-design daemon CLI source code, built and packaged at https://helix-mind.ai/cli/open-design/latest.tgz for use by the HelixMind /design slash command. Licenses: Apache-2.0 (root) + MIT (skills/*)
This commit is contained in:
176
e2e/tests/localized-content.test.ts
Normal file
176
e2e/tests/localized-content.test.ts
Normal file
@@ -0,0 +1,176 @@
|
||||
import { readdir, readFile, stat } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
declare global {
|
||||
interface ImportMeta {
|
||||
glob<T = unknown>(pattern: string, options: { eager: true }): Record<string, T>;
|
||||
}
|
||||
}
|
||||
|
||||
type LocalizedContentIds = {
|
||||
skills: string[];
|
||||
designSystems: string[];
|
||||
designSystemCategories: string[];
|
||||
promptTemplates: string[];
|
||||
promptTemplateCategories: string[];
|
||||
promptTemplateTags: string[];
|
||||
};
|
||||
|
||||
type LocalizedContentModule = {
|
||||
LOCALIZED_CONTENT_IDS: Record<string, LocalizedContentIds>;
|
||||
};
|
||||
|
||||
const repoRoot = fileURLToPath(new URL('../../', import.meta.url));
|
||||
const webContentModules = import.meta.glob<LocalizedContentModule>(
|
||||
'../../apps/web/src/i18n/content.ts',
|
||||
{ eager: true },
|
||||
);
|
||||
const localizedContentModule = Object.values(webContentModules)[0];
|
||||
|
||||
if (localizedContentModule == null) {
|
||||
throw new Error('Failed to load apps/web localized content ids');
|
||||
}
|
||||
|
||||
const { LOCALIZED_CONTENT_IDS } = localizedContentModule;
|
||||
|
||||
function sorted(values: Iterable<string>): string[] {
|
||||
return [...values].sort((a, b) => a.localeCompare(b));
|
||||
}
|
||||
|
||||
async function entriesWithFile(root: string, fileName: string): Promise<string[]> {
|
||||
const entries = await readdir(root, { withFileTypes: true });
|
||||
const ids: string[] = [];
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
const filePath = path.join(root, entry.name, fileName);
|
||||
try {
|
||||
if ((await stat(filePath)).isFile()) {
|
||||
ids.push(entry.name);
|
||||
}
|
||||
} catch {
|
||||
// Missing optional registry files are ignored, matching resource discovery.
|
||||
}
|
||||
}
|
||||
return sorted(ids);
|
||||
}
|
||||
|
||||
async function readSkillIds(): Promise<string[]> {
|
||||
const skillsRoot = path.join(repoRoot, 'skills');
|
||||
const dirs = await entriesWithFile(skillsRoot, 'SKILL.md');
|
||||
const ids = await Promise.all(
|
||||
dirs.map(async (dir) => {
|
||||
const raw = await readFile(path.join(skillsRoot, dir, 'SKILL.md'), 'utf8');
|
||||
return readFrontmatterName(raw) ?? dir;
|
||||
}),
|
||||
);
|
||||
return sorted(ids);
|
||||
}
|
||||
|
||||
async function readDesignSystemIds(): Promise<string[]> {
|
||||
return entriesWithFile(path.join(repoRoot, 'design-systems'), 'DESIGN.md');
|
||||
}
|
||||
|
||||
async function readDesignSystemCategories(): Promise<string[]> {
|
||||
const systemsRoot = path.join(repoRoot, 'design-systems');
|
||||
const ids = await readDesignSystemIds();
|
||||
const categories = await Promise.all(
|
||||
ids.map(async (id) => {
|
||||
const raw = await readFile(path.join(systemsRoot, id, 'DESIGN.md'), 'utf8');
|
||||
return /^>\s*Category:\s*(.+?)\s*$/im.exec(raw)?.[1] ?? 'Uncategorized';
|
||||
}),
|
||||
);
|
||||
return sorted(new Set(categories));
|
||||
}
|
||||
|
||||
async function readPromptTemplateSummaries(): Promise<
|
||||
Array<{ id: string; category: string; tags: string[] }>
|
||||
> {
|
||||
const templatesRoot = path.join(repoRoot, 'prompt-templates');
|
||||
const summaries: Array<{ id: string; category: string; tags: string[] }> = [];
|
||||
for (const surface of ['image', 'video']) {
|
||||
const dir = path.join(templatesRoot, surface);
|
||||
const entries = await readdir(dir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (!entry.isFile() || !entry.name.endsWith('.json')) continue;
|
||||
const raw = JSON.parse(await readFile(path.join(dir, entry.name), 'utf8')) as {
|
||||
id?: unknown;
|
||||
category?: unknown;
|
||||
tags?: unknown;
|
||||
};
|
||||
if (typeof raw.id !== 'string' || !raw.id) continue;
|
||||
summaries.push({
|
||||
id: raw.id,
|
||||
category: typeof raw.category === 'string' ? raw.category : 'General',
|
||||
tags: Array.isArray(raw.tags) ? raw.tags.filter((tag): tag is string => typeof tag === 'string') : [],
|
||||
});
|
||||
}
|
||||
}
|
||||
return summaries;
|
||||
}
|
||||
|
||||
function readFrontmatterName(src: string): string | null {
|
||||
const text = src.replace(/^\uFEFF/, '');
|
||||
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
|
||||
if (match == null) return null;
|
||||
const nameMatch = /^name:\s*(.*?)\s*$/im.exec(match[1] ?? '');
|
||||
if (nameMatch == null) return null;
|
||||
const name = unquoteYamlScalar(nameMatch[1] ?? '').trim();
|
||||
return name || null;
|
||||
}
|
||||
|
||||
function unquoteYamlScalar(value: string): string {
|
||||
const trimmed = value.trim();
|
||||
if (
|
||||
(trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
||||
(trimmed.startsWith("'") && trimmed.endsWith("'"))
|
||||
) {
|
||||
return trimmed.slice(1, -1);
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
describe('localized display content coverage', () => {
|
||||
for (const [locale, ids] of Object.entries(LOCALIZED_CONTENT_IDS)) {
|
||||
it(`covers every curated skill, design system, and prompt template for ${locale}`, async () => {
|
||||
const [skillIds, designSystemIds, promptTemplateSummaries] = await Promise.all([
|
||||
readSkillIds(),
|
||||
readDesignSystemIds(),
|
||||
readPromptTemplateSummaries(),
|
||||
]);
|
||||
|
||||
expect(sorted(ids.skills), 'skills display copy').toEqual(skillIds);
|
||||
expect(sorted(ids.designSystems), 'design-system summaries').toEqual(
|
||||
designSystemIds,
|
||||
);
|
||||
expect(sorted(ids.promptTemplates), 'prompt-template metadata').toEqual(
|
||||
sorted(promptTemplateSummaries.map((template) => template.id)),
|
||||
);
|
||||
});
|
||||
|
||||
it(`covers every curated display category and prompt tag for ${locale}`, async () => {
|
||||
const [designSystemCategories, promptTemplateSummaries] = await Promise.all([
|
||||
readDesignSystemCategories(),
|
||||
readPromptTemplateSummaries(),
|
||||
]);
|
||||
const promptTemplateCategories = new Set(
|
||||
promptTemplateSummaries.map((template) => template.category),
|
||||
);
|
||||
const promptTemplateTags = new Set(
|
||||
promptTemplateSummaries.flatMap((template) => template.tags),
|
||||
);
|
||||
|
||||
expect(sorted(ids.designSystemCategories)).toEqual(
|
||||
expect.arrayContaining(designSystemCategories),
|
||||
);
|
||||
expect(sorted(ids.promptTemplateCategories)).toEqual(
|
||||
expect.arrayContaining(sorted(promptTemplateCategories)),
|
||||
);
|
||||
expect(sorted(ids.promptTemplateTags)).toEqual(
|
||||
expect.arrayContaining(sorted(promptTemplateTags)),
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user