@jjlmoya/utils-games-development 1.65.0 → 1.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/tests/bibliography_wellformed_export.test.ts +46 -0
- package/src/tests/seo_wellformed_export.test.ts +65 -0
- package/src/tool/damageFormulaLab/bibliography.astro +3 -21
- package/src/tool/damageFormulaLab/seo.astro +7 -5
- package/src/tool/gameDeltaTimeFixedTimestepLab/bibliography.astro +3 -19
- package/src/tool/hitboxHurtboxAnimator/seo.astro +7 -5
package/package.json
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { readdirSync, readFileSync, existsSync } from 'fs';
|
|
3
|
+
import { join, relative } from 'path';
|
|
4
|
+
|
|
5
|
+
function findBibliographyAstroFiles(dir: string): string[] {
|
|
6
|
+
const files: string[] = [];
|
|
7
|
+
if (!existsSync(dir)) return files;
|
|
8
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
9
|
+
|
|
10
|
+
for (const entry of entries) {
|
|
11
|
+
const fullPath = join(dir, entry.name);
|
|
12
|
+
if (entry.isDirectory()) {
|
|
13
|
+
files.push(...findBibliographyAstroFiles(fullPath));
|
|
14
|
+
} else if (entry.isFile() && entry.name === 'bibliography.astro') {
|
|
15
|
+
files.push(fullPath);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return files;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const toolDir = join(process.cwd(), 'src', 'tool');
|
|
23
|
+
const bibliographyFiles = findBibliographyAstroFiles(toolDir);
|
|
24
|
+
|
|
25
|
+
describe('Bibliography Component Wellformed Export', () => {
|
|
26
|
+
it('found tool bibliography.astro components', () => {
|
|
27
|
+
expect(bibliographyFiles.length).toBeGreaterThan(0);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
bibliographyFiles.forEach((file) => {
|
|
31
|
+
const relativePath = relative(process.cwd(), file);
|
|
32
|
+
|
|
33
|
+
it(`${relativePath} should use SharedBibliography from @jjlmoya/utils-shared`, () => {
|
|
34
|
+
const content = readFileSync(file, 'utf-8');
|
|
35
|
+
|
|
36
|
+
const usesSharedComponent =
|
|
37
|
+
content.includes('@jjlmoya/utils-shared') &&
|
|
38
|
+
(content.includes('Bibliography') || content.includes('SharedBibliography'));
|
|
39
|
+
|
|
40
|
+
expect(
|
|
41
|
+
usesSharedComponent,
|
|
42
|
+
`File "${relativePath}" does not use the standard Bibliography component from @jjlmoya/utils-shared, resulting in unstyled or raw bibliography output.`,
|
|
43
|
+
).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { readdirSync, readFileSync, existsSync } from 'fs';
|
|
3
|
+
import { join, relative } from 'path';
|
|
4
|
+
|
|
5
|
+
function findSeoAstroFiles(dir: string): string[] {
|
|
6
|
+
const files: string[] = [];
|
|
7
|
+
if (!existsSync(dir)) return files;
|
|
8
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
9
|
+
|
|
10
|
+
for (const entry of entries) {
|
|
11
|
+
const fullPath = join(dir, entry.name);
|
|
12
|
+
if (entry.isDirectory()) {
|
|
13
|
+
files.push(...findSeoAstroFiles(fullPath));
|
|
14
|
+
} else if (entry.isFile() && entry.name === 'seo.astro') {
|
|
15
|
+
files.push(fullPath);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return files;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const toolDir = join(process.cwd(), 'src', 'tool');
|
|
23
|
+
const seoFiles = findSeoAstroFiles(toolDir);
|
|
24
|
+
|
|
25
|
+
describe('SEO Component Wellformed Export', () => {
|
|
26
|
+
it('found tool seo.astro components', () => {
|
|
27
|
+
expect(seoFiles.length).toBeGreaterThan(0);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
seoFiles.forEach((file) => {
|
|
31
|
+
const relativePath = relative(process.cwd(), file);
|
|
32
|
+
|
|
33
|
+
it(`${relativePath} should dynamically load SEO sections and use SEORenderer`, () => {
|
|
34
|
+
const content = readFileSync(file, 'utf-8');
|
|
35
|
+
|
|
36
|
+
const usesSeoRenderer =
|
|
37
|
+
content.includes('@jjlmoya/utils-shared') &&
|
|
38
|
+
(content.includes('SEORenderer') || content.includes('SEOArticle'));
|
|
39
|
+
|
|
40
|
+
const acquiresDynamicContent =
|
|
41
|
+
content.includes('.i18n') ||
|
|
42
|
+
content.includes('loader') ||
|
|
43
|
+
content.includes('await loader') ||
|
|
44
|
+
content.includes('.seo');
|
|
45
|
+
|
|
46
|
+
const isBrokenPattern =
|
|
47
|
+
/sections\s*=\s*\[\s*\]/.test(content) && !acquiresDynamicContent;
|
|
48
|
+
|
|
49
|
+
expect(
|
|
50
|
+
usesSeoRenderer,
|
|
51
|
+
`File "${relativePath}" does not import or use SEORenderer from @jjlmoya/utils-shared.`,
|
|
52
|
+
).toBe(true);
|
|
53
|
+
|
|
54
|
+
expect(
|
|
55
|
+
isBrokenPattern,
|
|
56
|
+
`File "${relativePath}" relies on a static sections=[] prop default without fetching content from entry.i18n, resulting in empty SEO text on consumers.`,
|
|
57
|
+
).toBe(false);
|
|
58
|
+
|
|
59
|
+
expect(
|
|
60
|
+
acquiresDynamicContent,
|
|
61
|
+
`File "${relativePath}" does not fetch dynamic i18n content for SEO rendering.`,
|
|
62
|
+
).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -1,24 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
title?: string;
|
|
6
|
-
entries?: BibliographyEntry[];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { title = 'References', entries = [] } = Astro.props;
|
|
2
|
+
import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { bibliographyEntries } from './bibliography';
|
|
10
4
|
---
|
|
11
5
|
|
|
12
|
-
{
|
|
13
|
-
<section class="damage-lab-references" aria-labelledby="damage-lab-reference-title">
|
|
14
|
-
<h2 id="damage-lab-reference-title">{title}</h2>
|
|
15
|
-
<ul>
|
|
16
|
-
{entries.map((entry) => <li><a href={entry.url} rel="noopener noreferrer" target="_blank">{entry.name}</a></li>)}
|
|
17
|
-
</ul>
|
|
18
|
-
</section>
|
|
19
|
-
)}
|
|
20
|
-
|
|
21
|
-
<style>
|
|
22
|
-
.damage-lab-references { margin-block: 2rem; }
|
|
23
|
-
.damage-lab-references a { color: var(--n-primary); }
|
|
24
|
-
</style>
|
|
6
|
+
<SharedBibliography links={bibliographyEntries} />
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { SEORenderer } from '@jjlmoya/utils-shared';
|
|
3
|
-
import
|
|
3
|
+
import { damageFormulaLab } from './entry';
|
|
4
|
+
import type { KnownLocale } from '../../types';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
|
-
locale?:
|
|
7
|
-
sections?: SEOSection[];
|
|
7
|
+
locale?: KnownLocale;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const { locale = '
|
|
10
|
+
const { locale = 'es' } = Astro.props;
|
|
11
|
+
const loader = damageFormulaLab.i18n[locale as KnownLocale] ?? damageFormulaLab.i18n.es ?? damageFormulaLab.i18n.en;
|
|
12
|
+
const content = loader ? await loader() : null;
|
|
11
13
|
---
|
|
12
14
|
|
|
13
|
-
<SEORenderer content={{ locale, sections }} />
|
|
15
|
+
{content?.seo && content.seo.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
title?: string;
|
|
6
|
-
entries?: BibliographyEntry[];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { title = 'References', entries = [] } = Astro.props;
|
|
2
|
+
import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { bibliographyEntries } from './bibliography';
|
|
10
4
|
---
|
|
11
5
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<style>
|
|
15
|
-
.gll-references {
|
|
16
|
-
margin-block: 2rem;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.gll-references a {
|
|
20
|
-
color: var(--n-primary);
|
|
21
|
-
}
|
|
22
|
-
</style>
|
|
6
|
+
<SharedBibliography links={bibliographyEntries} />
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { SEORenderer } from '@jjlmoya/utils-shared';
|
|
3
|
-
import
|
|
3
|
+
import { hitboxHurtboxAnimator } from './entry';
|
|
4
|
+
import type { KnownLocale } from '../../types';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
|
-
locale?:
|
|
7
|
-
sections?: SEOSection[];
|
|
7
|
+
locale?: KnownLocale;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const { locale = '
|
|
10
|
+
const { locale = 'es' } = Astro.props;
|
|
11
|
+
const loader = hitboxHurtboxAnimator.i18n[locale as KnownLocale] ?? hitboxHurtboxAnimator.i18n.es ?? hitboxHurtboxAnimator.i18n.en;
|
|
12
|
+
const content = loader ? await loader() : null;
|
|
11
13
|
---
|
|
12
14
|
|
|
13
|
-
<SEORenderer content={{ locale, sections }} />
|
|
15
|
+
{content?.seo && content.seo.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|