chore: fix prettier formatting, regenerate phase9 manifest, add missing config files (.env.example, .node-version, .nvmrc, CI workflow)
CI / test (push) Failing after 28s
CI / test (push) Failing after 28s
This commit is contained in:
@@ -3,22 +3,77 @@ import path from 'node:path';
|
||||
import crypto from 'node:crypto';
|
||||
const root = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..');
|
||||
const required = [
|
||||
'09_DEVELOPER_HANDOFF_v1.0.md','DECISION_LOG_v9.0.md','DEFINITION_OF_DONE_v1.0.md','OPEN_ISSUE_REGISTER_v1.0.csv',
|
||||
'tokens/design-tokens_v1.0.json','tokens/semantic-tokens_v1.0.css','components/COMPONENT_CONTRACTS_v1.0.md',
|
||||
'localization/ROUTE_MANIFEST_v1.0.json','localization/locales/en/homepage.json','localization/locales/fr/homepage.json','localization/locales/ar/homepage.json',
|
||||
'interaction/theme-bootstrap_v1.0.js','qa/QA_MATRIX_v1.0.csv','qa/ACCESSIBILITY_CHECKLIST_v1.0.csv','qa/PERFORMANCE_BUDGETS_v1.0.json'
|
||||
'09_DEVELOPER_HANDOFF_v1.0.md',
|
||||
'DECISION_LOG_v9.0.md',
|
||||
'DEFINITION_OF_DONE_v1.0.md',
|
||||
'OPEN_ISSUE_REGISTER_v1.0.csv',
|
||||
'tokens/design-tokens_v1.0.json',
|
||||
'tokens/semantic-tokens_v1.0.css',
|
||||
'components/COMPONENT_CONTRACTS_v1.0.md',
|
||||
'localization/ROUTE_MANIFEST_v1.0.json',
|
||||
'localization/locales/en/homepage.json',
|
||||
'localization/locales/fr/homepage.json',
|
||||
'localization/locales/ar/homepage.json',
|
||||
'interaction/theme-bootstrap_v1.0.js',
|
||||
'qa/QA_MATRIX_v1.0.csv',
|
||||
'qa/ACCESSIBILITY_CHECKLIST_v1.0.csv',
|
||||
'qa/PERFORMANCE_BUDGETS_v1.0.json',
|
||||
];
|
||||
const errors=[]; let checks=0;
|
||||
for (const file of required){ checks++; if(!fs.existsSync(path.join(root,file))) errors.push(`Missing ${file}`); }
|
||||
const readJson=(f)=>JSON.parse(fs.readFileSync(path.join(root,f),'utf8'));
|
||||
for (const file of ['tokens/design-tokens_v1.0.json','localization/ROUTE_MANIFEST_v1.0.json','qa/PERFORMANCE_BUDGETS_v1.0.json','qa/visual-regression-scenarios_v1.0.json']) { try{readJson(file);checks++;}catch(e){errors.push(`${file}: ${e.message}`);} }
|
||||
function shape(value){ if(Array.isArray(value)) return value.map(shape); if(value && typeof value==='object') return Object.fromEntries(Object.keys(value).sort().map(k=>[k,shape(value[k])])); return typeof value; }
|
||||
const locales=['en','fr','ar'].map(l=>readJson(`localization/locales/${l}/homepage.json`));
|
||||
const base=JSON.stringify(shape(locales[0]));
|
||||
for (let i=1;i<locales.length;i++){ checks++; if(JSON.stringify(shape(locales[i]))!==base) errors.push(`Locale shape mismatch: ${['en','fr','ar'][i]}`); }
|
||||
const routes=readJson('localization/ROUTE_MANIFEST_v1.0.json');
|
||||
for (const route of routes.routes){ for (const locale of routes.locales){ checks++; if(!(locale in route.slugs)) errors.push(`Route ${route.id} missing ${locale}`); } }
|
||||
const issueCsv=fs.readFileSync(path.join(root,'OPEN_ISSUE_REGISTER_v1.0.csv'),'utf8'); checks++; if(/,(Critical|High),[^\n]*,,/.test(issueCsv)) errors.push('Critical/High issue missing ownership data');
|
||||
const css=fs.readFileSync(path.join(root,'tokens/semantic-tokens_v1.0.css'),'utf8'); checks++; if(!css.includes('--color-action-conversion')) errors.push('Conversion semantic token missing');
|
||||
if(errors.length){ console.error(JSON.stringify({status:'FAILED',checks,errors},null,2)); process.exit(1); }
|
||||
console.log(JSON.stringify({status:'PASSED',checks,files:fs.readdirSync(root).length},null,2));
|
||||
const errors = [];
|
||||
let checks = 0;
|
||||
for (const file of required) {
|
||||
checks++;
|
||||
if (!fs.existsSync(path.join(root, file))) errors.push(`Missing ${file}`);
|
||||
}
|
||||
const readJson = (f) => JSON.parse(fs.readFileSync(path.join(root, f), 'utf8'));
|
||||
for (const file of [
|
||||
'tokens/design-tokens_v1.0.json',
|
||||
'localization/ROUTE_MANIFEST_v1.0.json',
|
||||
'qa/PERFORMANCE_BUDGETS_v1.0.json',
|
||||
'qa/visual-regression-scenarios_v1.0.json',
|
||||
]) {
|
||||
try {
|
||||
readJson(file);
|
||||
checks++;
|
||||
} catch (e) {
|
||||
errors.push(`${file}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
function shape(value) {
|
||||
if (Array.isArray(value)) return value.map(shape);
|
||||
if (value && typeof value === 'object')
|
||||
return Object.fromEntries(
|
||||
Object.keys(value)
|
||||
.sort()
|
||||
.map((k) => [k, shape(value[k])]),
|
||||
);
|
||||
return typeof value;
|
||||
}
|
||||
const locales = ['en', 'fr', 'ar'].map((l) => readJson(`localization/locales/${l}/homepage.json`));
|
||||
const base = JSON.stringify(shape(locales[0]));
|
||||
for (let i = 1; i < locales.length; i++) {
|
||||
checks++;
|
||||
if (JSON.stringify(shape(locales[i])) !== base)
|
||||
errors.push(`Locale shape mismatch: ${['en', 'fr', 'ar'][i]}`);
|
||||
}
|
||||
const routes = readJson('localization/ROUTE_MANIFEST_v1.0.json');
|
||||
for (const route of routes.routes) {
|
||||
for (const locale of routes.locales) {
|
||||
checks++;
|
||||
if (!(locale in route.slugs)) errors.push(`Route ${route.id} missing ${locale}`);
|
||||
}
|
||||
}
|
||||
const issueCsv = fs.readFileSync(path.join(root, 'OPEN_ISSUE_REGISTER_v1.0.csv'), 'utf8');
|
||||
checks++;
|
||||
if (/,(Critical|High),[^\n]*,,/.test(issueCsv))
|
||||
errors.push('Critical/High issue missing ownership data');
|
||||
const css = fs.readFileSync(path.join(root, 'tokens/semantic-tokens_v1.0.css'), 'utf8');
|
||||
checks++;
|
||||
if (!css.includes('--color-action-conversion')) errors.push('Conversion semantic token missing');
|
||||
if (errors.length) {
|
||||
console.error(JSON.stringify({ status: 'FAILED', checks, errors }, null, 2));
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(
|
||||
JSON.stringify({ status: 'PASSED', checks, files: fs.readdirSync(root).length }, null, 2),
|
||||
);
|
||||
|
||||
@@ -5,80 +5,56 @@
|
||||
{
|
||||
"id": "VR-001",
|
||||
"route": "/en",
|
||||
"viewport": [
|
||||
1440,
|
||||
1000
|
||||
],
|
||||
"viewport": [1440, 1000],
|
||||
"theme": "light",
|
||||
"state": "homepage-top"
|
||||
},
|
||||
{
|
||||
"id": "VR-002",
|
||||
"route": "/fr",
|
||||
"viewport": [
|
||||
1024,
|
||||
900
|
||||
],
|
||||
"viewport": [1024, 900],
|
||||
"theme": "dark",
|
||||
"state": "homepage-top"
|
||||
},
|
||||
{
|
||||
"id": "VR-003",
|
||||
"route": "/ar",
|
||||
"viewport": [
|
||||
390,
|
||||
844
|
||||
],
|
||||
"viewport": [390, 844],
|
||||
"theme": "light",
|
||||
"state": "homepage-top"
|
||||
},
|
||||
{
|
||||
"id": "VR-004",
|
||||
"route": "/ar",
|
||||
"viewport": [
|
||||
390,
|
||||
844
|
||||
],
|
||||
"viewport": [390, 844],
|
||||
"theme": "dark",
|
||||
"state": "drawer-open"
|
||||
},
|
||||
{
|
||||
"id": "VR-005",
|
||||
"route": "/en",
|
||||
"viewport": [
|
||||
390,
|
||||
844
|
||||
],
|
||||
"viewport": [390, 844],
|
||||
"theme": "light",
|
||||
"state": "demo-invalid"
|
||||
},
|
||||
{
|
||||
"id": "VR-006",
|
||||
"route": "/fr",
|
||||
"viewport": [
|
||||
768,
|
||||
1024
|
||||
],
|
||||
"viewport": [768, 1024],
|
||||
"theme": "dark",
|
||||
"state": "tour-step-3"
|
||||
},
|
||||
{
|
||||
"id": "VR-007",
|
||||
"route": "/ar",
|
||||
"viewport": [
|
||||
320,
|
||||
800
|
||||
],
|
||||
"viewport": [320, 800],
|
||||
"theme": "dark",
|
||||
"state": "reflow-gate"
|
||||
},
|
||||
{
|
||||
"id": "VR-008",
|
||||
"route": "/en",
|
||||
"viewport": [
|
||||
1440,
|
||||
1000
|
||||
],
|
||||
"viewport": [1440, 1000],
|
||||
"theme": "dark",
|
||||
"state": "pricing-and-final-cta"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user