@vyriy/dist 0.5.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/AGENTS.md +102 -0
- package/LICENSE +21 -0
- package/README.md +35 -0
- package/assets.d.ts +5 -0
- package/assets.js +37 -0
- package/bin/vyriy-dist.js +3 -0
- package/bin.d.ts +4 -0
- package/bin.js +29 -0
- package/cleanup.d.ts +2 -0
- package/cleanup.js +14 -0
- package/constants.d.ts +6 -0
- package/constants.js +6 -0
- package/dist.d.ts +2 -0
- package/dist.js +28 -0
- package/exports.d.ts +7 -0
- package/exports.js +81 -0
- package/file.d.ts +4 -0
- package/file.js +28 -0
- package/index.d.ts +2 -0
- package/index.js +1 -0
- package/package.d.ts +4 -0
- package/package.js +68 -0
- package/package.json +136 -0
- package/path.d.ts +3 -0
- package/path.js +7 -0
- package/root.d.ts +3 -0
- package/root.js +23 -0
- package/types.d.ts +29 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Project Agent Guide
|
|
2
|
+
|
|
3
|
+
This repository follows a calm engineering style: changes should be explicit, reusable, typed, documented, tested, and easy to reason about.
|
|
4
|
+
|
|
5
|
+
Use this guide as the default behavior for AI agents and contributors working in this repository. Prefer local package conventions when they are more specific than this document.
|
|
6
|
+
|
|
7
|
+
## Core Principles
|
|
8
|
+
|
|
9
|
+
- Prefer simple modules over clever frameworks or hidden conventions.
|
|
10
|
+
- Keep package and project boundaries explicit.
|
|
11
|
+
- Avoid project-specific coupling in reusable code.
|
|
12
|
+
- Extract only proven reusable behavior.
|
|
13
|
+
- Keep public APIs small, typed, documented, and stable.
|
|
14
|
+
- Prefer SSR-friendly and SSG-friendly code paths when working with frontend or shared code.
|
|
15
|
+
- Keep integrations replaceable and avoid hard coupling to a CMS, framework, vendor, or runtime host.
|
|
16
|
+
- Prefer infrastructure assumptions that are easy to deploy, observe, and replace.
|
|
17
|
+
- Prefer the option that is simpler to explain, easier to evolve, and calmer to maintain.
|
|
18
|
+
|
|
19
|
+
## File Shape
|
|
20
|
+
|
|
21
|
+
- Prefer one exported runtime method, component, helper, or class per production file when it stays readable.
|
|
22
|
+
- Prefer one matching test file per production file, for example `feature.ts` and `feature.test.ts`.
|
|
23
|
+
- Use focused folders when behavior naturally splits into several related files.
|
|
24
|
+
- Keep `index.ts` as a public re-export surface only. Do not place implementation logic in it.
|
|
25
|
+
- Use relative import and export specifiers that match the package module style.
|
|
26
|
+
- Use `.js` relative specifiers in TypeScript source for ESM/NodeNext packages.
|
|
27
|
+
- Add `types.ts` when public shared types are part of the package contract.
|
|
28
|
+
- Keep constants near the code that owns them unless they are shared or clarify repeated behavior.
|
|
29
|
+
|
|
30
|
+
## Public Surface
|
|
31
|
+
|
|
32
|
+
- Every new public export must be re-exported from the package or module public entry point.
|
|
33
|
+
- Add or update public-surface tests when exports change.
|
|
34
|
+
- Add JSDoc for public exports when behavior, parameters, return values, or usage expectations need explanation.
|
|
35
|
+
- Avoid exporting internal helpers only to make tests easier.
|
|
36
|
+
- Do not hand-maintain package `exports` maps unless the project has a real custom publishing need.
|
|
37
|
+
|
|
38
|
+
## Tests
|
|
39
|
+
|
|
40
|
+
- Cover public behavior and meaningful edge cases.
|
|
41
|
+
- Prefer behavior-focused tests over private implementation lock-in.
|
|
42
|
+
- Keep tests deterministic.
|
|
43
|
+
- Avoid real network, filesystem, timers, browser, or cloud dependencies unless the behavior specifically requires them.
|
|
44
|
+
- When mocking modules, install mocks before loading the module under test.
|
|
45
|
+
- Use focused validation when changing behavior.
|
|
46
|
+
|
|
47
|
+
Example validation commands:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
yarn test
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For workspaces, prefer the project convention, for example:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
yarn workspace <package-name> test
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
For Jest-based packages, focused validation may look like:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
yarn jest packages/<package> --runInBand --coverage=false
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Documentation
|
|
66
|
+
|
|
67
|
+
- Keep `README.md` concise and usage-oriented.
|
|
68
|
+
- Start package READMEs with `# <package>`.
|
|
69
|
+
- Document real public exports, supported options, and examples that actually work.
|
|
70
|
+
- Update docs when public behavior changes.
|
|
71
|
+
- Keep generated docs wrappers, such as `doc.mdx`, aligned with the README when the project uses them.
|
|
72
|
+
- For component packages, include visual documentation or stories for supported states and common usage.
|
|
73
|
+
|
|
74
|
+
## Components
|
|
75
|
+
|
|
76
|
+
- Prefer lightweight React components with TypeScript when working in React packages.
|
|
77
|
+
- Keep components SSR-friendly and avoid browser globals during render.
|
|
78
|
+
- Prefer composable props and predictable ergonomics.
|
|
79
|
+
- Put each public component in its own file with a matching test.
|
|
80
|
+
- Add stories or examples when a component has visual states, variants, or interaction states.
|
|
81
|
+
- Keep styling explicit and reusable. Avoid hidden theme assumptions unless they are part of the package contract.
|
|
82
|
+
|
|
83
|
+
## Change Discipline
|
|
84
|
+
|
|
85
|
+
- Keep changes scoped to the requested behavior.
|
|
86
|
+
- Avoid unrelated refactors and metadata churn.
|
|
87
|
+
- Sync implementation, tests, docs, examples, and public re-exports together.
|
|
88
|
+
- Do not introduce new dependencies unless they clearly reduce complexity or are already part of the project direction.
|
|
89
|
+
- Prefer small, reviewable changes over broad rewrites.
|
|
90
|
+
- Preserve existing conventions unless there is a clear reason to change them.
|
|
91
|
+
|
|
92
|
+
## Before Finishing
|
|
93
|
+
|
|
94
|
+
Check that the change is complete:
|
|
95
|
+
|
|
96
|
+
- Public exports are updated.
|
|
97
|
+
- Public-surface tests are updated when exports change.
|
|
98
|
+
- Matching unit tests exist for new behavior.
|
|
99
|
+
- README examples still match the real API.
|
|
100
|
+
- Visual docs, stories, or examples are updated for visible component behavior.
|
|
101
|
+
- TypeScript imports follow the package module style.
|
|
102
|
+
- No unrelated files, formatting churn, or generated artifacts were changed.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vyriy contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# @vyriy/dist
|
|
2
|
+
|
|
3
|
+
Vyriy distribution build CLI and package metadata preparation API.
|
|
4
|
+
|
|
5
|
+
## CLI
|
|
6
|
+
|
|
7
|
+
Install globally:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install --global @vyriy/dist
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Prepare compiled workspace packages for distribution:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
vyriy-dist
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## API
|
|
20
|
+
|
|
21
|
+
Install as a project dependency:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @vyriy/dist
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Run distribution preparation from code:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { dist } from '@vyriy/dist';
|
|
31
|
+
|
|
32
|
+
const code = await dist();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`dist()` copies root package metadata, prepares each `dist/<package>/package.json`, creates export maps, removes empty generated JavaScript files, and returns a process-style exit code.
|
package/assets.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PackageJson } from './types.js';
|
|
2
|
+
export declare const copyReadme: (packageDirectory: string) => Promise<void>;
|
|
3
|
+
export declare const resolveSourceAgentsPath: (packageAgentsPath: string, sharedAgentsPath: string, rootAgentsPath: string) => Promise<string>;
|
|
4
|
+
export declare const copyAgents: (packageDirectory: string, rootPackageJson: PackageJson) => Promise<boolean>;
|
|
5
|
+
export declare const copyLicense: (packageDirectory: string) => Promise<void>;
|
package/assets.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { copyFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { AGENTS_FILE, LICENSE_FILE, PACKAGES_DIR, README_FILE } from './constants.js';
|
|
4
|
+
import { hasFile } from './file.js';
|
|
5
|
+
export const copyReadme = async (packageDirectory) => {
|
|
6
|
+
const packageName = path.basename(packageDirectory);
|
|
7
|
+
const sourceReadmePath = path.join(PACKAGES_DIR, packageName, README_FILE);
|
|
8
|
+
if (await hasFile(sourceReadmePath)) {
|
|
9
|
+
await copyFile(sourceReadmePath, path.join(packageDirectory, README_FILE));
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export const resolveSourceAgentsPath = async (packageAgentsPath, sharedAgentsPath, rootAgentsPath) => {
|
|
13
|
+
if (await hasFile(packageAgentsPath)) {
|
|
14
|
+
return packageAgentsPath;
|
|
15
|
+
}
|
|
16
|
+
if (await hasFile(sharedAgentsPath)) {
|
|
17
|
+
return sharedAgentsPath;
|
|
18
|
+
}
|
|
19
|
+
return rootAgentsPath;
|
|
20
|
+
};
|
|
21
|
+
export const copyAgents = async (packageDirectory, rootPackageJson) => {
|
|
22
|
+
const packageName = path.basename(packageDirectory);
|
|
23
|
+
const packageAgentsPath = path.join(PACKAGES_DIR, packageName, AGENTS_FILE);
|
|
24
|
+
const sharedAgentsPath = path.join(PACKAGES_DIR, AGENTS_FILE);
|
|
25
|
+
const rootAgentsPath = typeof rootPackageJson.agents === 'string' ? rootPackageJson.agents.replace(/^\.\//, '') : '';
|
|
26
|
+
const sourceAgentsPath = await resolveSourceAgentsPath(packageAgentsPath, sharedAgentsPath, rootAgentsPath);
|
|
27
|
+
if (await hasFile(sourceAgentsPath)) {
|
|
28
|
+
await copyFile(sourceAgentsPath, path.join(packageDirectory, AGENTS_FILE));
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
};
|
|
33
|
+
export const copyLicense = async (packageDirectory) => {
|
|
34
|
+
if (await hasFile(LICENSE_FILE)) {
|
|
35
|
+
await copyFile(LICENSE_FILE, path.join(packageDirectory, LICENSE_FILE));
|
|
36
|
+
}
|
|
37
|
+
};
|
package/bin.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PackageJson } from './types.js';
|
|
2
|
+
export declare const getPackageBinFiles: (packageJson: PackageJson) => string[];
|
|
3
|
+
export declare const removePackageBinDeclarationFiles: (packageDirectory: string, packageJson: PackageJson) => Promise<void>;
|
|
4
|
+
export declare const makePackageBinsExecutable: (packageDirectory: string, packageJson: PackageJson) => Promise<void>;
|
package/bin.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { chmod, unlink } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { hasFile } from './file.js';
|
|
4
|
+
import { toPackageLocalPath } from './path.js';
|
|
5
|
+
export const getPackageBinFiles = (packageJson) => {
|
|
6
|
+
if (typeof packageJson.bin === 'string') {
|
|
7
|
+
return [packageJson.bin];
|
|
8
|
+
}
|
|
9
|
+
if (packageJson.bin && typeof packageJson.bin === 'object') {
|
|
10
|
+
return Object.values(packageJson.bin);
|
|
11
|
+
}
|
|
12
|
+
return [];
|
|
13
|
+
};
|
|
14
|
+
export const removePackageBinDeclarationFiles = async (packageDirectory, packageJson) => {
|
|
15
|
+
for (const binFile of getPackageBinFiles(packageJson)) {
|
|
16
|
+
const declarationFilePath = path.join(packageDirectory, toPackageLocalPath(binFile).replace(/\.js$/, '.d.ts'));
|
|
17
|
+
if (await hasFile(declarationFilePath)) {
|
|
18
|
+
await unlink(declarationFilePath);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export const makePackageBinsExecutable = async (packageDirectory, packageJson) => {
|
|
23
|
+
for (const binFile of getPackageBinFiles(packageJson)) {
|
|
24
|
+
const binFilePath = path.join(packageDirectory, toPackageLocalPath(binFile));
|
|
25
|
+
if (await hasFile(binFilePath)) {
|
|
26
|
+
await chmod(binFilePath, 0o755);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
package/cleanup.d.ts
ADDED
package/cleanup.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { readFile, unlink } from 'node:fs/promises';
|
|
2
|
+
import { readFiles } from './file.js';
|
|
3
|
+
export const isEmptyJavaScriptContent = (content) => {
|
|
4
|
+
const normalizedContent = content.trim();
|
|
5
|
+
return normalizedContent.length === 0 || normalizedContent === 'export {};';
|
|
6
|
+
};
|
|
7
|
+
export const removeEmptyJavaScriptFiles = async (packageDirectory) => {
|
|
8
|
+
const files = await readFiles(packageDirectory);
|
|
9
|
+
for (const file of files) {
|
|
10
|
+
if (file.endsWith('.js') && isEmptyJavaScriptContent(await readFile(file, 'utf8'))) {
|
|
11
|
+
await unlink(file);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
};
|
package/constants.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const DIST_DIR = "dist";
|
|
2
|
+
export declare const AGENTS_FILE = "AGENTS.md";
|
|
3
|
+
export declare const LICENSE_FILE = "LICENSE";
|
|
4
|
+
export declare const PACKAGE_JSON_FILE = "package.json";
|
|
5
|
+
export declare const PACKAGES_DIR = "packages";
|
|
6
|
+
export declare const README_FILE = "README.md";
|
package/constants.js
ADDED
package/dist.d.ts
ADDED
package/dist.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { readdir } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { DIST_DIR, PACKAGE_JSON_FILE } from './constants.js';
|
|
4
|
+
import { hasFile, readJson } from './file.js';
|
|
5
|
+
import { distPackage } from './package.js';
|
|
6
|
+
import { distRoot } from './root.js';
|
|
7
|
+
export const dist = async () => {
|
|
8
|
+
const previousCwd = process.cwd();
|
|
9
|
+
try {
|
|
10
|
+
process.chdir(process.cwd());
|
|
11
|
+
const rootPackageJson = await readJson(PACKAGE_JSON_FILE);
|
|
12
|
+
await distRoot();
|
|
13
|
+
const entries = await readdir(DIST_DIR, { withFileTypes: true });
|
|
14
|
+
const packageJsonPaths = entries
|
|
15
|
+
.filter((entry) => entry.isDirectory())
|
|
16
|
+
.map((entry) => path.join(DIST_DIR, entry.name, PACKAGE_JSON_FILE))
|
|
17
|
+
.sort((left, right) => left.localeCompare(right));
|
|
18
|
+
for (const packageJsonPath of packageJsonPaths) {
|
|
19
|
+
if (await hasFile(packageJsonPath)) {
|
|
20
|
+
await distPackage(packageJsonPath, rootPackageJson);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
process.chdir(previousCwd);
|
|
27
|
+
}
|
|
28
|
+
};
|
package/exports.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ExportTarget, PackageJson } from './types.js';
|
|
2
|
+
export declare const getMissingExportTarget: (file: string, line: string) => Promise<string | undefined>;
|
|
3
|
+
export declare const removeMissingJavaScriptExports: (packageDirectory: string) => Promise<void>;
|
|
4
|
+
export declare const getJavaScriptFiles: (packageDirectory: string) => Promise<string[]>;
|
|
5
|
+
export declare const getPackageMain: (packageDirectory: string, packageJson: PackageJson, javaScriptFiles: string[]) => Promise<string | undefined>;
|
|
6
|
+
export declare const createExportTarget: (javaScriptFile: string) => ExportTarget;
|
|
7
|
+
export declare const createExports: (mainFile: string, javaScriptFiles: string[]) => Record<string, ExportTarget>;
|
package/exports.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getPackageBinFiles } from './bin.js';
|
|
4
|
+
import { hasFile, readFiles } from './file.js';
|
|
5
|
+
import { toPackagePath, toPosixPath } from './path.js';
|
|
6
|
+
const exportTargetPattern = /^\s*export(?:\s+\*|\s+\{[^}]*\})\s+from\s+['"](\..+\.js)['"];?\s*$/;
|
|
7
|
+
export const getMissingExportTarget = async (file, line) => {
|
|
8
|
+
const exportTarget = exportTargetPattern.exec(line)?.[1];
|
|
9
|
+
if (!exportTarget) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
const exportTargetPath = path.resolve(path.dirname(file), exportTarget);
|
|
13
|
+
return (await hasFile(exportTargetPath)) ? undefined : exportTargetPath;
|
|
14
|
+
};
|
|
15
|
+
export const removeMissingJavaScriptExports = async (packageDirectory) => {
|
|
16
|
+
const files = await readFiles(packageDirectory);
|
|
17
|
+
for (const file of files) {
|
|
18
|
+
if (!file.endsWith('.js')) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const content = await readFile(file, 'utf8');
|
|
22
|
+
const lines = content.split('\n');
|
|
23
|
+
const retainedLines = [];
|
|
24
|
+
for (const line of lines) {
|
|
25
|
+
if (!(await getMissingExportTarget(file, line))) {
|
|
26
|
+
retainedLines.push(line);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (retainedLines.length !== lines.length) {
|
|
30
|
+
await writeFile(file, retainedLines.join('\n'));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
export const getJavaScriptFiles = async (packageDirectory) => {
|
|
35
|
+
const files = await readFiles(packageDirectory);
|
|
36
|
+
const javaScriptFiles = [];
|
|
37
|
+
for (const file of files) {
|
|
38
|
+
const relativeFile = toPosixPath(path.relative(packageDirectory, file));
|
|
39
|
+
const declarationFile = path.join(packageDirectory, relativeFile.replace(/\.js$/, '.d.ts'));
|
|
40
|
+
if (relativeFile.endsWith('.js') && !relativeFile.endsWith('.test.js') && (await hasFile(declarationFile))) {
|
|
41
|
+
javaScriptFiles.push(relativeFile);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return javaScriptFiles.sort((left, right) => left.localeCompare(right));
|
|
45
|
+
};
|
|
46
|
+
export const getPackageMain = async (packageDirectory, packageJson, javaScriptFiles) => {
|
|
47
|
+
if (packageJson.main?.endsWith('.js')) {
|
|
48
|
+
const mainPath = packageJson.main.replace(/^\.\//, '');
|
|
49
|
+
if (await hasFile(path.join(packageDirectory, mainPath))) {
|
|
50
|
+
return toPosixPath(mainPath);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (javaScriptFiles.includes('index.js')) {
|
|
54
|
+
return 'index.js';
|
|
55
|
+
}
|
|
56
|
+
if (getPackageBinFiles(packageJson).length > 0) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return javaScriptFiles[0];
|
|
60
|
+
};
|
|
61
|
+
export const createExportTarget = (javaScriptFile) => {
|
|
62
|
+
const packagePath = toPackagePath(javaScriptFile);
|
|
63
|
+
return {
|
|
64
|
+
types: packagePath.replace(/\.js$/, '.d.ts'),
|
|
65
|
+
import: packagePath,
|
|
66
|
+
default: packagePath,
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
export const createExports = (mainFile, javaScriptFiles) => {
|
|
70
|
+
const exports = {
|
|
71
|
+
'.': createExportTarget(mainFile),
|
|
72
|
+
};
|
|
73
|
+
for (const javaScriptFile of javaScriptFiles) {
|
|
74
|
+
const packagePath = toPackagePath(javaScriptFile);
|
|
75
|
+
const extensionlessPackagePath = packagePath.replace(/\.js$/, '');
|
|
76
|
+
const target = createExportTarget(javaScriptFile);
|
|
77
|
+
exports[extensionlessPackagePath] = target;
|
|
78
|
+
exports[packagePath] = target;
|
|
79
|
+
}
|
|
80
|
+
return exports;
|
|
81
|
+
};
|
package/file.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const hasFile: (filePath: string) => Promise<boolean>;
|
|
2
|
+
export declare const readJson: <Value>(filePath: string) => Promise<Value>;
|
|
3
|
+
export declare const writeJson: (filePath: string, value: unknown) => Promise<void>;
|
|
4
|
+
export declare const readFiles: (directory: string) => Promise<string[]>;
|
package/file.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { readdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export const hasFile = async (filePath) => {
|
|
4
|
+
try {
|
|
5
|
+
return (await stat(filePath)).isFile();
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
export const readJson = async (filePath) => {
|
|
12
|
+
const content = await readFile(filePath, 'utf8');
|
|
13
|
+
return JSON.parse(content);
|
|
14
|
+
};
|
|
15
|
+
export const writeJson = async (filePath, value) => {
|
|
16
|
+
await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
17
|
+
};
|
|
18
|
+
export const readFiles = async (directory) => {
|
|
19
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
20
|
+
const files = await Promise.all(entries.map(async (entry) => {
|
|
21
|
+
const entryPath = path.join(directory, entry.name);
|
|
22
|
+
if (entry.isDirectory()) {
|
|
23
|
+
return readFiles(entryPath);
|
|
24
|
+
}
|
|
25
|
+
return entry.isFile() ? [entryPath] : [];
|
|
26
|
+
}));
|
|
27
|
+
return files.flat();
|
|
28
|
+
};
|
package/index.d.ts
ADDED
package/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist.js';
|
package/package.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PackageJson, Repository } from './types.js';
|
|
2
|
+
export declare const createPackageRepository: (rootPackageJson: PackageJson, packageDirectory: string) => Repository | undefined;
|
|
3
|
+
export declare const syncPackageRuntimeMetadata: (packageJson: PackageJson, rootPackageJson: PackageJson) => void;
|
|
4
|
+
export declare const distPackage: (packageJsonPath: string, rootPackageJson: PackageJson) => Promise<void>;
|
package/package.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { copyAgents, copyLicense, copyReadme } from './assets.js';
|
|
3
|
+
import { makePackageBinsExecutable, removePackageBinDeclarationFiles } from './bin.js';
|
|
4
|
+
import { AGENTS_FILE, PACKAGES_DIR } from './constants.js';
|
|
5
|
+
import { removeEmptyJavaScriptFiles } from './cleanup.js';
|
|
6
|
+
import { createExports, getJavaScriptFiles, getPackageMain, removeMissingJavaScriptExports } from './exports.js';
|
|
7
|
+
import { readJson, writeJson } from './file.js';
|
|
8
|
+
import { toPackagePath, toPosixPath } from './path.js';
|
|
9
|
+
export const createPackageRepository = (rootPackageJson, packageDirectory) => {
|
|
10
|
+
const rootRepository = rootPackageJson.repository;
|
|
11
|
+
if (!rootRepository) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
...rootRepository,
|
|
16
|
+
directory: toPosixPath(path.join(PACKAGES_DIR, path.basename(packageDirectory))),
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export const syncPackageRuntimeMetadata = (packageJson, rootPackageJson) => {
|
|
20
|
+
if (packageJson.name !== 'vyriy') {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
packageJson.packageManager = rootPackageJson.packageManager;
|
|
24
|
+
packageJson.engines = rootPackageJson.engines;
|
|
25
|
+
};
|
|
26
|
+
export const distPackage = async (packageJsonPath, rootPackageJson) => {
|
|
27
|
+
const packageDirectory = path.dirname(packageJsonPath);
|
|
28
|
+
const packageJson = await readJson(packageJsonPath);
|
|
29
|
+
await removeEmptyJavaScriptFiles(packageDirectory);
|
|
30
|
+
await removeMissingJavaScriptExports(packageDirectory);
|
|
31
|
+
await removeEmptyJavaScriptFiles(packageDirectory);
|
|
32
|
+
await removePackageBinDeclarationFiles(packageDirectory, packageJson);
|
|
33
|
+
const javaScriptFiles = await getJavaScriptFiles(packageDirectory);
|
|
34
|
+
await copyLicense(packageDirectory);
|
|
35
|
+
await copyReadme(packageDirectory);
|
|
36
|
+
const hasAgents = await copyAgents(packageDirectory, rootPackageJson);
|
|
37
|
+
delete packageJson.private;
|
|
38
|
+
if (hasAgents && rootPackageJson.agents) {
|
|
39
|
+
packageJson.agents = toPackagePath(AGENTS_FILE);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
delete packageJson.agents;
|
|
43
|
+
}
|
|
44
|
+
if (rootPackageJson.license) {
|
|
45
|
+
packageJson.license = rootPackageJson.license;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
delete packageJson.license;
|
|
49
|
+
}
|
|
50
|
+
const repository = createPackageRepository(rootPackageJson, packageDirectory);
|
|
51
|
+
if (repository) {
|
|
52
|
+
packageJson.repository = repository;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
delete packageJson.repository;
|
|
56
|
+
}
|
|
57
|
+
syncPackageRuntimeMetadata(packageJson, rootPackageJson);
|
|
58
|
+
if (javaScriptFiles.length > 0) {
|
|
59
|
+
const mainFile = await getPackageMain(packageDirectory, packageJson, javaScriptFiles);
|
|
60
|
+
if (mainFile) {
|
|
61
|
+
packageJson.main = toPackagePath(mainFile);
|
|
62
|
+
packageJson.types = toPackagePath(mainFile).replace(/\.js$/, '.d.ts');
|
|
63
|
+
packageJson.exports = createExports(mainFile, javaScriptFiles);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
await makePackageBinsExecutable(packageDirectory, packageJson);
|
|
67
|
+
await writeJson(packageJsonPath, packageJson);
|
|
68
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vyriy/dist",
|
|
3
|
+
"version": "0.5.2",
|
|
4
|
+
"description": "Vyriy distribution build CLI.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=24.0.0"
|
|
8
|
+
},
|
|
9
|
+
"bin": "./bin/vyriy-dist.js",
|
|
10
|
+
"agents": "./AGENTS.md",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/evheniy/vyriy",
|
|
15
|
+
"directory": "packages/dist"
|
|
16
|
+
},
|
|
17
|
+
"main": "./index.js",
|
|
18
|
+
"types": "./index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./index.d.ts",
|
|
22
|
+
"import": "./index.js",
|
|
23
|
+
"default": "./index.js"
|
|
24
|
+
},
|
|
25
|
+
"./assets": {
|
|
26
|
+
"types": "./assets.d.ts",
|
|
27
|
+
"import": "./assets.js",
|
|
28
|
+
"default": "./assets.js"
|
|
29
|
+
},
|
|
30
|
+
"./assets.js": {
|
|
31
|
+
"types": "./assets.d.ts",
|
|
32
|
+
"import": "./assets.js",
|
|
33
|
+
"default": "./assets.js"
|
|
34
|
+
},
|
|
35
|
+
"./bin": {
|
|
36
|
+
"types": "./bin.d.ts",
|
|
37
|
+
"import": "./bin.js",
|
|
38
|
+
"default": "./bin.js"
|
|
39
|
+
},
|
|
40
|
+
"./bin.js": {
|
|
41
|
+
"types": "./bin.d.ts",
|
|
42
|
+
"import": "./bin.js",
|
|
43
|
+
"default": "./bin.js"
|
|
44
|
+
},
|
|
45
|
+
"./cleanup": {
|
|
46
|
+
"types": "./cleanup.d.ts",
|
|
47
|
+
"import": "./cleanup.js",
|
|
48
|
+
"default": "./cleanup.js"
|
|
49
|
+
},
|
|
50
|
+
"./cleanup.js": {
|
|
51
|
+
"types": "./cleanup.d.ts",
|
|
52
|
+
"import": "./cleanup.js",
|
|
53
|
+
"default": "./cleanup.js"
|
|
54
|
+
},
|
|
55
|
+
"./constants": {
|
|
56
|
+
"types": "./constants.d.ts",
|
|
57
|
+
"import": "./constants.js",
|
|
58
|
+
"default": "./constants.js"
|
|
59
|
+
},
|
|
60
|
+
"./constants.js": {
|
|
61
|
+
"types": "./constants.d.ts",
|
|
62
|
+
"import": "./constants.js",
|
|
63
|
+
"default": "./constants.js"
|
|
64
|
+
},
|
|
65
|
+
"./dist": {
|
|
66
|
+
"types": "./dist.d.ts",
|
|
67
|
+
"import": "./dist.js",
|
|
68
|
+
"default": "./dist.js"
|
|
69
|
+
},
|
|
70
|
+
"./dist.js": {
|
|
71
|
+
"types": "./dist.d.ts",
|
|
72
|
+
"import": "./dist.js",
|
|
73
|
+
"default": "./dist.js"
|
|
74
|
+
},
|
|
75
|
+
"./exports": {
|
|
76
|
+
"types": "./exports.d.ts",
|
|
77
|
+
"import": "./exports.js",
|
|
78
|
+
"default": "./exports.js"
|
|
79
|
+
},
|
|
80
|
+
"./exports.js": {
|
|
81
|
+
"types": "./exports.d.ts",
|
|
82
|
+
"import": "./exports.js",
|
|
83
|
+
"default": "./exports.js"
|
|
84
|
+
},
|
|
85
|
+
"./file": {
|
|
86
|
+
"types": "./file.d.ts",
|
|
87
|
+
"import": "./file.js",
|
|
88
|
+
"default": "./file.js"
|
|
89
|
+
},
|
|
90
|
+
"./file.js": {
|
|
91
|
+
"types": "./file.d.ts",
|
|
92
|
+
"import": "./file.js",
|
|
93
|
+
"default": "./file.js"
|
|
94
|
+
},
|
|
95
|
+
"./index": {
|
|
96
|
+
"types": "./index.d.ts",
|
|
97
|
+
"import": "./index.js",
|
|
98
|
+
"default": "./index.js"
|
|
99
|
+
},
|
|
100
|
+
"./index.js": {
|
|
101
|
+
"types": "./index.d.ts",
|
|
102
|
+
"import": "./index.js",
|
|
103
|
+
"default": "./index.js"
|
|
104
|
+
},
|
|
105
|
+
"./package": {
|
|
106
|
+
"types": "./package.d.ts",
|
|
107
|
+
"import": "./package.js",
|
|
108
|
+
"default": "./package.js"
|
|
109
|
+
},
|
|
110
|
+
"./package.js": {
|
|
111
|
+
"types": "./package.d.ts",
|
|
112
|
+
"import": "./package.js",
|
|
113
|
+
"default": "./package.js"
|
|
114
|
+
},
|
|
115
|
+
"./path": {
|
|
116
|
+
"types": "./path.d.ts",
|
|
117
|
+
"import": "./path.js",
|
|
118
|
+
"default": "./path.js"
|
|
119
|
+
},
|
|
120
|
+
"./path.js": {
|
|
121
|
+
"types": "./path.d.ts",
|
|
122
|
+
"import": "./path.js",
|
|
123
|
+
"default": "./path.js"
|
|
124
|
+
},
|
|
125
|
+
"./root": {
|
|
126
|
+
"types": "./root.d.ts",
|
|
127
|
+
"import": "./root.js",
|
|
128
|
+
"default": "./root.js"
|
|
129
|
+
},
|
|
130
|
+
"./root.js": {
|
|
131
|
+
"types": "./root.d.ts",
|
|
132
|
+
"import": "./root.js",
|
|
133
|
+
"default": "./root.js"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
package/path.d.ts
ADDED
package/path.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
export const toPosixPath = (value) => value.split(path.sep).join('/');
|
|
3
|
+
export const toPackagePath = (value) => {
|
|
4
|
+
const normalizedValue = toPosixPath(value);
|
|
5
|
+
return `./${normalizedValue.replace(/^\.\//, '')}`;
|
|
6
|
+
};
|
|
7
|
+
export const toPackageLocalPath = (filePath) => filePath.replace(/^\.\//, '');
|
package/root.d.ts
ADDED
package/root.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { copyFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { DIST_DIR, LICENSE_FILE, PACKAGE_JSON_FILE, README_FILE } from './constants.js';
|
|
4
|
+
import { hasFile, readJson, writeJson } from './file.js';
|
|
5
|
+
export const copyRootFile = async (fileName) => {
|
|
6
|
+
if (await hasFile(fileName)) {
|
|
7
|
+
await copyFile(fileName, path.join(DIST_DIR, fileName));
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
export const distRootPackageJson = async () => {
|
|
11
|
+
const packageJson = await readJson(PACKAGE_JSON_FILE);
|
|
12
|
+
delete packageJson.agents;
|
|
13
|
+
delete packageJson.dependencies;
|
|
14
|
+
delete packageJson.packageManager;
|
|
15
|
+
delete packageJson.scripts;
|
|
16
|
+
delete packageJson.devDependencies;
|
|
17
|
+
await writeJson(path.join(DIST_DIR, PACKAGE_JSON_FILE), packageJson);
|
|
18
|
+
};
|
|
19
|
+
export const distRoot = async () => {
|
|
20
|
+
await copyRootFile(README_FILE);
|
|
21
|
+
await copyRootFile(LICENSE_FILE);
|
|
22
|
+
await distRootPackageJson();
|
|
23
|
+
};
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type Command = () => Promise<number>;
|
|
2
|
+
export type ExportTarget = {
|
|
3
|
+
readonly default: string;
|
|
4
|
+
readonly import: string;
|
|
5
|
+
readonly types: string;
|
|
6
|
+
};
|
|
7
|
+
export type Repository = {
|
|
8
|
+
readonly directory?: string;
|
|
9
|
+
readonly type: string;
|
|
10
|
+
readonly url: string;
|
|
11
|
+
};
|
|
12
|
+
export type PackageJson = {
|
|
13
|
+
agents?: string;
|
|
14
|
+
bin?: string | Record<string, string>;
|
|
15
|
+
dependencies?: unknown;
|
|
16
|
+
devDependencies?: unknown;
|
|
17
|
+
engines?: unknown;
|
|
18
|
+
exports?: Record<string, ExportTarget>;
|
|
19
|
+
license?: string;
|
|
20
|
+
main?: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
packageManager?: unknown;
|
|
23
|
+
private?: boolean;
|
|
24
|
+
repository?: Repository;
|
|
25
|
+
scripts?: unknown;
|
|
26
|
+
types?: string;
|
|
27
|
+
workspaces?: unknown;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
};
|