@zhin.js/page 1.1.0 → 1.1.2
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/README.md +2 -2
- package/lib/provider.js +23 -7
- package/package.json +3 -3
- package/src/provider.ts +29 -7
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# @zhin.js/page
|
|
2
2
|
|
|
3
|
-
标准 Page Feature provider。它把插件或项目根的平面 `pages
|
|
3
|
+
标准 Page Feature provider。它把插件或项目根的平面 `pages/*/index.ts|tsx` 发现为 owner-bound Page manifest,并从 Plugin path 确定性生成 route;未加 `$` 的文件不会被加载为页面。
|
|
4
4
|
|
|
5
5
|
## Convention
|
|
6
6
|
|
|
7
7
|
- `pages/status.tsx` -> localName `status`。
|
|
8
8
|
- Root route 为 `/p-status`;`root/a/b` 的 route 为 `/a/b/p-status`。
|
|
9
9
|
- 首版不递归,不支持 `index`、`[param]` 或 route metadata override。
|
|
10
|
-
-
|
|
10
|
+
- `pages/nav/`、`pages/footer/` 由 Layout Feature 处理,不属于普通 Page。
|
|
11
11
|
|
|
12
12
|
## Client Boundary
|
|
13
13
|
|
package/lib/provider.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { join,
|
|
1
|
+
import { join, sep } from 'node:path';
|
|
2
2
|
import { featureId } from '@zhin.js/plugin-runtime';
|
|
3
|
-
import { defineFeatureProvider } from '@zhin.js/feature-kit';
|
|
3
|
+
import { defineFeatureProvider, } from '@zhin.js/feature-kit';
|
|
4
4
|
import { parsePageArtifact } from './definition.js';
|
|
5
5
|
import { PageIndex } from './page-index.js';
|
|
6
6
|
export const pageFeatureId = featureId('zhin.page');
|
|
@@ -11,11 +11,20 @@ const pageFiles = {
|
|
|
11
11
|
const entries = [...await context.host.list(directory)]
|
|
12
12
|
.sort((left, right) => left.name.localeCompare(right.name));
|
|
13
13
|
for (const entry of entries) {
|
|
14
|
-
if (entry.kind !== '
|
|
14
|
+
if (entry.kind !== 'directory' || !isPageName(entry.name)
|
|
15
|
+
|| entry.name === 'nav' || entry.name === 'footer')
|
|
16
|
+
continue;
|
|
17
|
+
const moduleDirectory = join(directory, entry.name);
|
|
18
|
+
const moduleEntries = await context.host.list(moduleDirectory);
|
|
19
|
+
const index = preferredPageIndex(moduleEntries, context.packageRoot.split(sep).includes('node_modules'));
|
|
20
|
+
if (!index)
|
|
15
21
|
continue;
|
|
16
22
|
yield {
|
|
17
|
-
localName:
|
|
18
|
-
source: join(
|
|
23
|
+
localName: entry.name,
|
|
24
|
+
source: join(moduleDirectory, index),
|
|
25
|
+
relatedSources: moduleEntries
|
|
26
|
+
.filter((candidate) => candidate.kind === 'file' && candidate.name !== index)
|
|
27
|
+
.map((candidate) => join(moduleDirectory, candidate.name)),
|
|
19
28
|
target: 'client',
|
|
20
29
|
};
|
|
21
30
|
}
|
|
@@ -40,8 +49,15 @@ const pageFeature = defineFeatureProvider({
|
|
|
40
49
|
},
|
|
41
50
|
},
|
|
42
51
|
});
|
|
43
|
-
function
|
|
44
|
-
return /^[a-z0-9][a-z0-9-]
|
|
52
|
+
function isPageName(value) {
|
|
53
|
+
return /^[a-z0-9][a-z0-9-]*$/u.test(value);
|
|
54
|
+
}
|
|
55
|
+
function preferredPageIndex(entries, preferJavaScript) {
|
|
56
|
+
const files = new Set(entries.filter((entry) => entry.kind === 'file').map((entry) => entry.name));
|
|
57
|
+
const extensions = preferJavaScript
|
|
58
|
+
? ['js', 'mjs', 'cjs', 'ts', 'tsx']
|
|
59
|
+
: ['ts', 'tsx', 'js', 'mjs', 'cjs'];
|
|
60
|
+
return extensions.map((extension) => `index.${extension}`).find((name) => files.has(name));
|
|
45
61
|
}
|
|
46
62
|
export { pageFeature };
|
|
47
63
|
export default pageFeature;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/page",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Convention-based Page capability Feature for Zhin.js plugins",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"src"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
+
"@zhin.js/plugin-runtime": "1.1.11",
|
|
20
21
|
"@zhin.js/console-contract": "1.1.0",
|
|
21
|
-
"@zhin.js/feature-kit": "1.1.
|
|
22
|
-
"@zhin.js/plugin-runtime": "1.1.9"
|
|
22
|
+
"@zhin.js/feature-kit": "1.1.2"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^26.1.2",
|
package/src/provider.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { join,
|
|
1
|
+
import { join, sep } from 'node:path';
|
|
2
2
|
import { featureId } from '@zhin.js/plugin-runtime';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
defineFeatureProvider,
|
|
5
|
+
type SourceConvention,
|
|
6
|
+
} from '@zhin.js/feature-kit';
|
|
4
7
|
import { parsePageArtifact } from './definition.js';
|
|
5
8
|
import { PageIndex } from './page-index.js';
|
|
6
9
|
|
|
@@ -13,10 +16,18 @@ const pageFiles: SourceConvention = {
|
|
|
13
16
|
const entries = [...await context.host.list(directory)]
|
|
14
17
|
.sort((left, right) => left.name.localeCompare(right.name));
|
|
15
18
|
for (const entry of entries) {
|
|
16
|
-
if (entry.kind !== '
|
|
19
|
+
if (entry.kind !== 'directory' || !isPageName(entry.name)
|
|
20
|
+
|| entry.name === 'nav' || entry.name === 'footer') continue;
|
|
21
|
+
const moduleDirectory = join(directory, entry.name);
|
|
22
|
+
const moduleEntries = await context.host.list(moduleDirectory);
|
|
23
|
+
const index = preferredPageIndex(moduleEntries, context.packageRoot.split(sep).includes('node_modules'));
|
|
24
|
+
if (!index) continue;
|
|
17
25
|
yield {
|
|
18
|
-
localName:
|
|
19
|
-
source: join(
|
|
26
|
+
localName: entry.name,
|
|
27
|
+
source: join(moduleDirectory, index),
|
|
28
|
+
relatedSources: moduleEntries
|
|
29
|
+
.filter((candidate) => candidate.kind === 'file' && candidate.name !== index)
|
|
30
|
+
.map((candidate) => join(moduleDirectory, candidate.name)),
|
|
20
31
|
target: 'client',
|
|
21
32
|
};
|
|
22
33
|
}
|
|
@@ -42,8 +53,19 @@ const pageFeature = defineFeatureProvider({
|
|
|
42
53
|
},
|
|
43
54
|
});
|
|
44
55
|
|
|
45
|
-
function
|
|
46
|
-
return /^[a-z0-9][a-z0-9-]
|
|
56
|
+
function isPageName(value: string): boolean {
|
|
57
|
+
return /^[a-z0-9][a-z0-9-]*$/u.test(value);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function preferredPageIndex(
|
|
61
|
+
entries: readonly { readonly name: string; readonly kind: 'file' | 'directory' }[],
|
|
62
|
+
preferJavaScript: boolean,
|
|
63
|
+
): string | undefined {
|
|
64
|
+
const files = new Set(entries.filter((entry) => entry.kind === 'file').map((entry) => entry.name));
|
|
65
|
+
const extensions = preferJavaScript
|
|
66
|
+
? ['js', 'mjs', 'cjs', 'ts', 'tsx']
|
|
67
|
+
: ['ts', 'tsx', 'js', 'mjs', 'cjs'];
|
|
68
|
+
return extensions.map((extension) => `index.${extension}`).find((name) => files.has(name));
|
|
47
69
|
}
|
|
48
70
|
|
|
49
71
|
export { pageFeature };
|