@bleedingdev/modern-js-create 3.2.0-ultramodern.72 → 3.2.0-ultramodern.74
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/dist/index.js +45 -39
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -983,8 +983,8 @@ function createRootPackageJson(scope, packageSource, remotes = []) {
|
|
|
983
983
|
build: `${remoteBuildPrefix}pnpm --filter "./apps/shell-super-app" run build && pnpm ultramodern:assert-mf-types`,
|
|
984
984
|
format: "oxfmt . '!repos/**'",
|
|
985
985
|
'format:check': "oxfmt --check . '!repos/**'",
|
|
986
|
-
lint: 'oxlint
|
|
987
|
-
'lint:fix': 'oxlint
|
|
986
|
+
lint: 'oxlint .',
|
|
987
|
+
'lint:fix': 'oxlint . --fix',
|
|
988
988
|
typecheck: `pnpm -r --filter "@${scope}/*" typecheck`,
|
|
989
989
|
'cloudflare:build': `${remoteCloudflareBuildPrefix}pnpm --filter "./apps/shell-super-app" run cloudflare:build && pnpm ultramodern:assert-mf-types`,
|
|
990
990
|
'cloudflare:deploy': `${remoteCloudflareDeployPrefix}pnpm --filter "./apps/shell-super-app" run cloudflare:deploy`,
|
|
@@ -1151,10 +1151,7 @@ function createPackageTsConfig(packageDir, includeApi = false) {
|
|
|
1151
1151
|
if (includeApi) include.push('api', 'shared');
|
|
1152
1152
|
return {
|
|
1153
1153
|
extends: `${relativeRootFor(packageDir)}/tsconfig.base.json`,
|
|
1154
|
-
include
|
|
1155
|
-
exclude: [
|
|
1156
|
-
'src/modern-tanstack'
|
|
1157
|
-
]
|
|
1154
|
+
include
|
|
1158
1155
|
};
|
|
1159
1156
|
}
|
|
1160
1157
|
function createAppPackage(scope, app, packageSource, enableTailwind, remotes = []) {
|
|
@@ -4510,9 +4507,8 @@ function createWorkspaceI18nBoundaryValidationScript() {
|
|
|
4510
4507
|
return `#!/usr/bin/env node
|
|
4511
4508
|
import fs from 'node:fs';
|
|
4512
4509
|
import path from 'node:path';
|
|
4513
|
-
import { fileURLToPath } from 'node:url';
|
|
4514
4510
|
|
|
4515
|
-
const root = path.resolve(
|
|
4511
|
+
const root = path.resolve(import.meta.dirname, '..');
|
|
4516
4512
|
const sourceRoots = ['apps', 'verticals'];
|
|
4517
4513
|
const languageConditionalPattern =
|
|
4518
4514
|
/\\b(language|locale|lng|currentLanguage)\\s*={0,2}={1,2}\\s*['"][a-z-]+['"]\\s*\\?\\s*([^:;\\n]+)\\s*:\\s*([^;\\n})]+)/gu;
|
|
@@ -4532,11 +4528,11 @@ const visibleCopyAttributes = new Set([
|
|
|
4532
4528
|
'title',
|
|
4533
4529
|
]);
|
|
4534
4530
|
|
|
4535
|
-
|
|
4531
|
+
const fail = (message) => {
|
|
4536
4532
|
throw new Error(message);
|
|
4537
|
-
}
|
|
4533
|
+
};
|
|
4538
4534
|
|
|
4539
|
-
|
|
4535
|
+
const walk = (directory, files = []) => {
|
|
4540
4536
|
if (!fs.existsSync(directory)) {
|
|
4541
4537
|
return files;
|
|
4542
4538
|
}
|
|
@@ -4552,43 +4548,37 @@ function walk(directory, files = []) {
|
|
|
4552
4548
|
}
|
|
4553
4549
|
}
|
|
4554
4550
|
return files;
|
|
4555
|
-
}
|
|
4551
|
+
};
|
|
4556
4552
|
|
|
4557
|
-
|
|
4558
|
-
return path.relative(root, filePath).replace(/\\\\/gu, '/');
|
|
4559
|
-
}
|
|
4553
|
+
const relative = (filePath) => path.relative(root, filePath).replaceAll('\\\\', '/');
|
|
4560
4554
|
|
|
4561
|
-
|
|
4562
|
-
return /\\.(?:ts|tsx|js|jsx)$/u.test(filePath);
|
|
4563
|
-
}
|
|
4555
|
+
const isSourceFile = (filePath) => /\\.(?:ts|tsx|js|jsx)$/u.test(filePath);
|
|
4564
4556
|
|
|
4565
|
-
|
|
4557
|
+
const isLocaleJson = (filePath) => {
|
|
4566
4558
|
const normalized = relative(filePath);
|
|
4567
4559
|
return /\\/locales\\/(en|cs)\\/[^/]+\\.json$/u.test(normalized);
|
|
4568
|
-
}
|
|
4560
|
+
};
|
|
4569
4561
|
|
|
4570
|
-
|
|
4571
|
-
return fs.readFileSync(filePath, 'utf8');
|
|
4572
|
-
}
|
|
4562
|
+
const readText = (filePath) => fs.readFileSync(filePath, 'utf-8');
|
|
4573
4563
|
|
|
4574
|
-
|
|
4564
|
+
const branchIsUserCopy = (branch) => {
|
|
4575
4565
|
const value = branch.trim().replace(/,$/u, '');
|
|
4576
4566
|
if (allowedLanguageConditionalBranches.has(value)) {
|
|
4577
4567
|
return false;
|
|
4578
4568
|
}
|
|
4579
4569
|
return /^['"][^'"]{2,}['"]$/u.test(value);
|
|
4580
|
-
}
|
|
4570
|
+
};
|
|
4581
4571
|
|
|
4582
|
-
|
|
4572
|
+
const checkRuntimeResources = (filePath, text) => {
|
|
4583
4573
|
if (!relative(filePath).endsWith('/src/modern.runtime.ts')) {
|
|
4584
4574
|
return;
|
|
4585
4575
|
}
|
|
4586
4576
|
if (/initOptions\\s*:\\s*\\{[\\s\\S]*?\\bresources\\s*:/u.test(text)) {
|
|
4587
4577
|
fail(\`\${relative(filePath)} must not inline i18n resources in modern.runtime.ts; use locale JSON files.\`);
|
|
4588
4578
|
}
|
|
4589
|
-
}
|
|
4579
|
+
};
|
|
4590
4580
|
|
|
4591
|
-
|
|
4581
|
+
const checkLanguageConditionals = (filePath, text) => {
|
|
4592
4582
|
for (const match of text.matchAll(languageConditionalPattern)) {
|
|
4593
4583
|
const [, name, whenTrue = '', whenFalse = ''] = match;
|
|
4594
4584
|
if (branchIsUserCopy(whenTrue) || branchIsUserCopy(whenFalse)) {
|
|
@@ -4597,9 +4587,9 @@ function checkLanguageConditionals(filePath, text) {
|
|
|
4597
4587
|
);
|
|
4598
4588
|
}
|
|
4599
4589
|
}
|
|
4600
|
-
}
|
|
4590
|
+
};
|
|
4601
4591
|
|
|
4602
|
-
|
|
4592
|
+
const checkLiteralVisibleAttributes = (filePath, text) => {
|
|
4603
4593
|
if (!filePath.endsWith('.tsx') && !filePath.endsWith('.jsx')) {
|
|
4604
4594
|
return;
|
|
4605
4595
|
}
|
|
@@ -4611,17 +4601,17 @@ function checkLiteralVisibleAttributes(filePath, text) {
|
|
|
4611
4601
|
);
|
|
4612
4602
|
}
|
|
4613
4603
|
}
|
|
4614
|
-
}
|
|
4604
|
+
};
|
|
4615
4605
|
|
|
4616
|
-
|
|
4606
|
+
const checkSplitPhraseKeys = (filePath, text) => {
|
|
4617
4607
|
if (/t\\(\\s*['"][^'"]+\\.(?:prefix|suffix|before|after)['"]\\s*\\)/u.test(text)) {
|
|
4618
4608
|
fail(
|
|
4619
4609
|
\`\${relative(filePath)} uses split phrase translation keys. Keep translator-owned phrases whole.\`,
|
|
4620
4610
|
);
|
|
4621
4611
|
}
|
|
4622
|
-
}
|
|
4612
|
+
};
|
|
4623
4613
|
|
|
4624
|
-
|
|
4614
|
+
const checkBoundaryAttributes = (filePath, text) => {
|
|
4625
4615
|
if (!filePath.endsWith('.tsx') && !filePath.endsWith('.jsx')) {
|
|
4626
4616
|
return;
|
|
4627
4617
|
}
|
|
@@ -4630,9 +4620,9 @@ function checkBoundaryAttributes(filePath, text) {
|
|
|
4630
4620
|
\`\${relative(filePath)} uses legacy data-mf-* boundary attributes. Use data-modern-boundary-id and data-modern-mf-expose.\`,
|
|
4631
4621
|
);
|
|
4632
4622
|
}
|
|
4633
|
-
}
|
|
4623
|
+
};
|
|
4634
4624
|
|
|
4635
|
-
|
|
4625
|
+
const visitLocaleKeys = (value, visitor, pathParts = []) => {
|
|
4636
4626
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
4637
4627
|
return;
|
|
4638
4628
|
}
|
|
@@ -4641,9 +4631,9 @@ function visitLocaleKeys(value, visitor, pathParts = []) {
|
|
|
4641
4631
|
visitor(key, child, nextPath);
|
|
4642
4632
|
visitLocaleKeys(child, visitor, nextPath);
|
|
4643
4633
|
}
|
|
4644
|
-
}
|
|
4634
|
+
};
|
|
4645
4635
|
|
|
4646
|
-
|
|
4636
|
+
const checkPluralResources = (filePath, json) => {
|
|
4647
4637
|
const language = relative(filePath).split('/locales/')[1]?.split('/')[0];
|
|
4648
4638
|
const requiredSuffixes =
|
|
4649
4639
|
language === 'cs' ? ['one', 'few', 'many', 'other'] : ['one', 'other'];
|
|
@@ -4673,7 +4663,7 @@ function checkPluralResources(filePath, json) {
|
|
|
4673
4663
|
}
|
|
4674
4664
|
}
|
|
4675
4665
|
}
|
|
4676
|
-
}
|
|
4666
|
+
};
|
|
4677
4667
|
|
|
4678
4668
|
const sourceFiles = sourceRoots.flatMap(sourceRoot =>
|
|
4679
4669
|
walk(path.join(root, sourceRoot)).filter(filePath => isSourceFile(filePath)),
|
|
@@ -5085,6 +5075,7 @@ async function fetchText(url) {
|
|
|
5085
5075
|
status: response.status,
|
|
5086
5076
|
accessControlAllowOrigin: response.headers.get('access-control-allow-origin'),
|
|
5087
5077
|
contentType: response.headers.get('content-type'),
|
|
5078
|
+
link: response.headers.get('link'),
|
|
5088
5079
|
body: await response.text(),
|
|
5089
5080
|
};
|
|
5090
5081
|
}
|
|
@@ -5179,6 +5170,21 @@ async function validateApp(app, publicUrl) {
|
|
|
5179
5170
|
expectedAppId && ssr.body.includes(\`data-app-id="\${expectedAppId}"\`),
|
|
5180
5171
|
\`\${app.id} SSR response is missing CSS root marker \${cssRootSelector}\`,
|
|
5181
5172
|
);
|
|
5173
|
+
const cssPreloadLinkHeader = ssr.link ?? '';
|
|
5174
|
+
evidence.assertions.push({
|
|
5175
|
+
type: 'css-preload-link-header',
|
|
5176
|
+
actual: cssPreloadLinkHeader,
|
|
5177
|
+
status:
|
|
5178
|
+
cssPreloadLinkHeader.includes('rel=preload') &&
|
|
5179
|
+
cssPreloadLinkHeader.includes('as=style')
|
|
5180
|
+
? 'pass'
|
|
5181
|
+
: 'fail',
|
|
5182
|
+
});
|
|
5183
|
+
assert(
|
|
5184
|
+
cssPreloadLinkHeader.includes('rel=preload') &&
|
|
5185
|
+
cssPreloadLinkHeader.includes('as=style'),
|
|
5186
|
+
\`\${app.id} SSR response is missing CSS preload Link headers\`,
|
|
5187
|
+
);
|
|
5182
5188
|
|
|
5183
5189
|
const manifestRoute = routes.mfManifest ?? '/mf-manifest.json';
|
|
5184
5190
|
const manifest = await fetchText(joinUrl(publicUrl, manifestRoute));
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=20"
|
|
23
23
|
},
|
|
24
|
-
"version": "3.2.0-ultramodern.
|
|
24
|
+
"version": "3.2.0-ultramodern.74",
|
|
25
25
|
"types": "./dist/types/index.d.ts",
|
|
26
26
|
"main": "./dist/index.js",
|
|
27
27
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@types/node": "^25.9.1",
|
|
42
42
|
"@typescript/native-preview": "7.0.0-dev.20260527.2",
|
|
43
43
|
"tsx": "^4.22.3",
|
|
44
|
-
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.2.0-ultramodern.
|
|
44
|
+
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.2.0-ultramodern.74"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -54,6 +54,6 @@
|
|
|
54
54
|
"start": "node ./dist/index.js"
|
|
55
55
|
},
|
|
56
56
|
"ultramodern": {
|
|
57
|
-
"frameworkVersion": "3.2.0-ultramodern.
|
|
57
|
+
"frameworkVersion": "3.2.0-ultramodern.74"
|
|
58
58
|
}
|
|
59
59
|
}
|