@comity-dev/package-tools 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Filippo Bovo and 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.
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * comity-normalize-exports — canonical export declaration normalizer for Comity packages.
4
+ *
5
+ * Usage:
6
+ * comity-normalize-exports [options]
7
+ *
8
+ * Options:
9
+ * --help, -h Show this help
10
+ * --check Check mode - exit with code 1 if changes needed
11
+ *
12
+ * The tool processes all index.ts files in packages/ and normalizes
13
+ * export declaration ordering (type exports first, then runtime exports,
14
+ * both sorted alphabetically by module specifier).
15
+ */
16
+ export {};
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * comity-normalize-exports — canonical export declaration normalizer for Comity packages.
4
+ *
5
+ * Usage:
6
+ * comity-normalize-exports [options]
7
+ *
8
+ * Options:
9
+ * --help, -h Show this help
10
+ * --check Check mode - exit with code 1 if changes needed
11
+ *
12
+ * The tool processes all index.ts files in packages/ and normalizes
13
+ * export declaration ordering (type exports first, then runtime exports,
14
+ * both sorted alphabetically by module specifier).
15
+ */
16
+ import { readdir, readFile, writeFile } from "node:fs/promises";
17
+ import { dirname, join, resolve, relative } from "node:path";
18
+ import { fileURLToPath } from "node:url";
19
+ import * as ts from "typescript";
20
+ const __dirname = dirname(fileURLToPath(import.meta.url));
21
+ const REPO_ROOT = resolve(__dirname, "..", "..", "..", ".."); // monorepo root (from dist/bin/)
22
+ const PACKAGES_DIR = join(REPO_ROOT, "packages");
23
+ const EXCLUDED_DIRS = new Set([
24
+ "node_modules",
25
+ "dist",
26
+ ".turbo",
27
+ "coverage",
28
+ "__tests__",
29
+ "__mocks__",
30
+ ]);
31
+ const EXCLUDED_PACKAGES = new Set([]);
32
+ function shouldProcessFile(filePath) {
33
+ const relPath = relative(REPO_ROOT, filePath);
34
+ const parts = relPath.split("/");
35
+ for (const part of parts) {
36
+ if (EXCLUDED_DIRS.has(part))
37
+ return false;
38
+ }
39
+ return true;
40
+ }
41
+ function getPackageName(filePath) {
42
+ const relPath = relative(PACKAGES_DIR, filePath);
43
+ const pkgDir = relPath.split("/")[0];
44
+ return `@comity/${pkgDir}`;
45
+ }
46
+ function isExcludedPackage(pkgName) {
47
+ return EXCLUDED_PACKAGES.has(pkgName);
48
+ }
49
+ function isSetupIndex(filePath) {
50
+ return filePath.includes("/src/setup/index.ts");
51
+ }
52
+ async function findTypeScriptFiles(dir) {
53
+ const files = [];
54
+ let entries;
55
+ try {
56
+ entries = await readdir(dir, { withFileTypes: true });
57
+ }
58
+ catch {
59
+ return files;
60
+ }
61
+ for (const entry of entries) {
62
+ const fullPath = join(dir, entry.name);
63
+ if (!shouldProcessFile(fullPath))
64
+ continue;
65
+ if (entry.isDirectory()) {
66
+ files.push(...(await findTypeScriptFiles(fullPath)));
67
+ }
68
+ else if (entry.name === "index.ts" && fullPath.includes("/src/")) {
69
+ files.push(fullPath);
70
+ }
71
+ }
72
+ return files;
73
+ }
74
+ function getSourceFile(filePath, content) {
75
+ return ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
76
+ }
77
+ function getExportDeclarations(sourceFile) {
78
+ const exports = [];
79
+ function visit(node) {
80
+ if (ts.isExportDeclaration(node)) {
81
+ exports.push(node);
82
+ }
83
+ ts.forEachChild(node, visit);
84
+ }
85
+ visit(sourceFile);
86
+ return exports;
87
+ }
88
+ function getExportInfo(exportDecl, sourceFile) {
89
+ const text = exportDecl.getText(sourceFile);
90
+ const isTypeOnly = exportDecl.isTypeOnly === true;
91
+ const moduleSpecifier = exportDecl.moduleSpecifier?.getText(sourceFile) ?? "";
92
+ const start = exportDecl.getStart(sourceFile);
93
+ const end = exportDecl.getEnd();
94
+ return {
95
+ text,
96
+ isTypeOnly,
97
+ moduleSpecifier: moduleSpecifier.replace(/^["']|["']$/g, ""),
98
+ start,
99
+ end,
100
+ node: exportDecl,
101
+ };
102
+ }
103
+ function getSortKey(info) {
104
+ return info.moduleSpecifier || "zzz-local";
105
+ }
106
+ function normalizeExports(content, sourceFile) {
107
+ const exportDecls = getExportDeclarations(sourceFile);
108
+ if (exportDecls.length === 0)
109
+ return content;
110
+ const exportInfos = exportDecls.map((decl) => getExportInfo(decl, sourceFile));
111
+ const typeExports = exportInfos.filter((info) => info.isTypeOnly);
112
+ const runtimeExports = exportInfos.filter((info) => !info.isTypeOnly);
113
+ if (typeExports.length === 0 && runtimeExports.length === 0) {
114
+ return content;
115
+ }
116
+ // exportInfos is guaranteed non-empty here because we checked above
117
+ const firstExport = exportInfos[0];
118
+ const lastExport = exportInfos[exportInfos.length - 1];
119
+ typeExports.sort((a, b) => getSortKey(a).localeCompare(getSortKey(b)));
120
+ runtimeExports.sort((a, b) => getSortKey(a).localeCompare(getSortKey(b)));
121
+ const lines = content.split(/\r?\n/);
122
+ const startLine = sourceFile.getLineAndCharacterOfPosition(firstExport.start).line;
123
+ const endLine = sourceFile.getLineAndCharacterOfPosition(lastExport.end).line;
124
+ const beforeExports = lines.slice(0, startLine);
125
+ const afterExports = lines.slice(endLine + 1);
126
+ const newExportLines = [];
127
+ if (typeExports.length > 0) {
128
+ newExportLines.push(...typeExports.map((info) => info.text));
129
+ }
130
+ if (typeExports.length > 0 && runtimeExports.length > 0) {
131
+ newExportLines.push("");
132
+ }
133
+ if (runtimeExports.length > 0) {
134
+ newExportLines.push(...runtimeExports.map((info) => info.text));
135
+ }
136
+ const newContent = [...beforeExports, ...newExportLines, ...afterExports].join("\n");
137
+ return newContent;
138
+ }
139
+ async function processFile(filePath) {
140
+ const content = await readFile(filePath, "utf8");
141
+ const sourceFile = getSourceFile(filePath, content);
142
+ const newContent = normalizeExports(content, sourceFile);
143
+ return { filePath, original: content, normalized: newContent, changed: content !== newContent };
144
+ }
145
+ function printHelp() {
146
+ console.log(`comity-normalize-exports — canonical export declaration normalizer for Comity packages
147
+
148
+ Usage:
149
+ comity-normalize-exports [options]
150
+
151
+ Options:
152
+ --help, -h Show this help
153
+ --check Check mode - exit with code 1 if changes needed
154
+
155
+ The tool processes all index.ts files in packages/ and normalizes
156
+ export declaration ordering (type exports first, then runtime exports,
157
+ both sorted alphabetically by module specifier).`);
158
+ }
159
+ async function main() {
160
+ const args = process.argv.slice(2);
161
+ const checkMode = args.includes("--check") || args.includes("-c");
162
+ const helpMode = args.includes("--help") || args.includes("-h");
163
+ if (helpMode) {
164
+ printHelp();
165
+ process.exit(0);
166
+ }
167
+ const files = await findTypeScriptFiles(PACKAGES_DIR);
168
+ console.log(`Found ${files.length} index.ts files to process`);
169
+ let hasChanges = false;
170
+ const changedFiles = [];
171
+ for (const filePath of files) {
172
+ if (!shouldProcessFile(filePath))
173
+ continue;
174
+ const pkgName = getPackageName(filePath);
175
+ if (isExcludedPackage(pkgName))
176
+ continue;
177
+ const result = await processFile(filePath);
178
+ if (result.changed) {
179
+ hasChanges = true;
180
+ changedFiles.push({ path: result.filePath, pkg: pkgName });
181
+ if (!checkMode) {
182
+ await writeFile(result.filePath, result.normalized, "utf8");
183
+ console.log(`Normalized: ${relative(REPO_ROOT, result.filePath)}`);
184
+ }
185
+ else {
186
+ console.log(`Would normalize: ${relative(REPO_ROOT, result.filePath)}`);
187
+ }
188
+ }
189
+ }
190
+ if (checkMode) {
191
+ if (hasChanges) {
192
+ console.log(`\n${changedFiles.length} file(s) would be changed:`);
193
+ for (const f of changedFiles) {
194
+ console.log(` - ${f.pkg}: ${relative(REPO_ROOT, f.path)}`);
195
+ }
196
+ process.exit(1);
197
+ }
198
+ else {
199
+ console.log("All export declarations are already normalized.");
200
+ process.exit(0);
201
+ }
202
+ }
203
+ else {
204
+ if (hasChanges) {
205
+ console.log(`\nNormalized ${changedFiles.length} file(s).`);
206
+ }
207
+ else {
208
+ console.log("All export declarations are already normalized.");
209
+ }
210
+ }
211
+ }
212
+ main().catch((error) => {
213
+ console.error(error);
214
+ process.exit(1);
215
+ });
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * comity-normalize-package-json — canonical key-order normalizer for `package.json`
4
+ * files in a Comity workspace.
5
+ *
6
+ * Usage:
7
+ * comity-normalize-package-json [options]
8
+ *
9
+ * Options:
10
+ * --help, -h Show this help
11
+ * --check Check mode - exit with code 1 if changes needed
12
+ * --packages-dir <dir> Directory containing packages (default: packages)
13
+ * --package-pattern <re> Regex pattern for package names (default: ^@comity/)
14
+ * --repo-root <dir> Repository root (default: auto-detected)
15
+ *
16
+ * Exit codes:
17
+ * 0 - Success (no changes needed in check mode, or changes applied)
18
+ * 1 - Changes needed (check mode) or error
19
+ */
20
+ export {};
@@ -0,0 +1,303 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * comity-normalize-package-json — canonical key-order normalizer for `package.json`
4
+ * files in a Comity workspace.
5
+ *
6
+ * Usage:
7
+ * comity-normalize-package-json [options]
8
+ *
9
+ * Options:
10
+ * --help, -h Show this help
11
+ * --check Check mode - exit with code 1 if changes needed
12
+ * --packages-dir <dir> Directory containing packages (default: packages)
13
+ * --package-pattern <re> Regex pattern for package names (default: ^@comity/)
14
+ * --repo-root <dir> Repository root (default: auto-detected)
15
+ *
16
+ * Exit codes:
17
+ * 0 - Success (no changes needed in check mode, or changes applied)
18
+ * 1 - Changes needed (check mode) or error
19
+ */
20
+ import { readdir, readFile, writeFile } from "node:fs/promises";
21
+ import { join, resolve } from "node:path";
22
+ const CANONICAL_TOP_LEVEL_ORDER = [
23
+ "name",
24
+ "version",
25
+ "description",
26
+ "type",
27
+ "private",
28
+ "author",
29
+ "license",
30
+ "comity",
31
+ "homepage",
32
+ "repository",
33
+ "bugs",
34
+ "engines",
35
+ "keywords",
36
+ "scripts",
37
+ "files",
38
+ "main",
39
+ "module",
40
+ "types",
41
+ "exports",
42
+ "typesVersions",
43
+ "publishConfig",
44
+ "sideEffects",
45
+ "peerDependencies",
46
+ "dependencies",
47
+ "optionalDependencies",
48
+ "devDependencies",
49
+ ];
50
+ const CANONICAL_SCRIPTS_ORDER = ["build", "prepublishOnly", "dev", "test", "type-check", "lint"];
51
+ const CANONICAL_KEYWORD_PRIORITY = ["comity", "comityjs"];
52
+ function sortDependencies(deps) {
53
+ if (!deps || typeof deps !== "object")
54
+ return {};
55
+ const comity = {};
56
+ const scoped = {};
57
+ const unscoped = {};
58
+ for (const [key, value] of Object.entries(deps)) {
59
+ if (key.startsWith("@comity/")) {
60
+ comity[key] = value;
61
+ }
62
+ else if (key.startsWith("@")) {
63
+ scoped[key] = value;
64
+ }
65
+ else {
66
+ unscoped[key] = value;
67
+ }
68
+ }
69
+ const sortObj = (obj) => Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a.localeCompare(b)));
70
+ return { ...sortObj(comity), ...sortObj(scoped), ...sortObj(unscoped) };
71
+ }
72
+ function sortKeywords(keywords) {
73
+ if (!Array.isArray(keywords))
74
+ return [];
75
+ const priority = new Set(CANONICAL_KEYWORD_PRIORITY);
76
+ const priorityKeywords = [];
77
+ const otherKeywords = [];
78
+ for (const kw of keywords) {
79
+ if (priority.has(kw)) {
80
+ priorityKeywords.push(kw);
81
+ }
82
+ else {
83
+ otherKeywords.push(kw);
84
+ }
85
+ }
86
+ return [...priorityKeywords.sort(), ...otherKeywords.sort()];
87
+ }
88
+ function sortExports(exports) {
89
+ if (!exports || typeof exports !== "object")
90
+ return {};
91
+ const result = {};
92
+ if (exports["."] !== undefined) {
93
+ result["."] = exports["."];
94
+ }
95
+ const subpaths = Object.keys(exports)
96
+ .filter((k) => k !== "." && k !== "./package.json")
97
+ .sort();
98
+ for (const subpath of subpaths) {
99
+ result[subpath] = exports[subpath];
100
+ }
101
+ if (exports["./package.json"] !== undefined) {
102
+ result["./package.json"] = exports["./package.json"];
103
+ }
104
+ for (const [key, value] of Object.entries(result)) {
105
+ if (value && typeof value === "object" && !Array.isArray(value)) {
106
+ const conditionOrder = ["import", "require", "types", "default"];
107
+ const sortedConditions = {};
108
+ const valueObj = value;
109
+ for (const cond of conditionOrder) {
110
+ if (valueObj[cond] !== undefined) {
111
+ sortedConditions[cond] = valueObj[cond];
112
+ }
113
+ }
114
+ for (const [cond, val] of Object.entries(valueObj)) {
115
+ if (!conditionOrder.includes(cond)) {
116
+ sortedConditions[cond] = val;
117
+ }
118
+ }
119
+ result[key] = sortedConditions;
120
+ }
121
+ }
122
+ return result;
123
+ }
124
+ function sortTypesVersions(typesVersions) {
125
+ if (!typesVersions || typeof typesVersions !== "object")
126
+ return {};
127
+ const result = {};
128
+ for (const [version, mapping] of Object.entries(typesVersions)) {
129
+ if (mapping && typeof mapping === "object") {
130
+ result[version] = Object.fromEntries(Object.entries(mapping).sort(([a], [b]) => a.localeCompare(b)));
131
+ }
132
+ }
133
+ return result;
134
+ }
135
+ function sortScripts(scripts) {
136
+ if (!scripts || typeof scripts !== "object")
137
+ return {};
138
+ const result = {};
139
+ for (const script of CANONICAL_SCRIPTS_ORDER) {
140
+ if (scripts[script] !== undefined) {
141
+ result[script] = scripts[script];
142
+ }
143
+ }
144
+ for (const [key, value] of Object.entries(scripts)) {
145
+ if (!CANONICAL_SCRIPTS_ORDER.includes(key)) {
146
+ result[key] = value;
147
+ }
148
+ }
149
+ return result;
150
+ }
151
+ function normalizePackageJson(pkgJson) {
152
+ const normalized = {};
153
+ for (const key of CANONICAL_TOP_LEVEL_ORDER) {
154
+ if (pkgJson[key] !== undefined) {
155
+ let value = pkgJson[key];
156
+ if (["peerDependencies", "dependencies", "optionalDependencies", "devDependencies"].includes(key)) {
157
+ value = sortDependencies(value);
158
+ }
159
+ else if (key === "keywords") {
160
+ value = sortKeywords(value);
161
+ }
162
+ else if (key === "exports") {
163
+ value = sortExports(value);
164
+ }
165
+ else if (key === "typesVersions") {
166
+ value = sortTypesVersions(value);
167
+ }
168
+ else if (key === "scripts") {
169
+ value = sortScripts(value);
170
+ }
171
+ normalized[key] = value;
172
+ }
173
+ }
174
+ for (const [key, value] of Object.entries(pkgJson)) {
175
+ if (!CANONICAL_TOP_LEVEL_ORDER.includes(key)) {
176
+ normalized[key] = value;
177
+ }
178
+ }
179
+ return normalized;
180
+ }
181
+ async function readPackageJson(pkgPath) {
182
+ const content = await readFile(pkgPath, "utf8");
183
+ return JSON.parse(content);
184
+ }
185
+ async function writePackageJson(pkgPath, pkgJson) {
186
+ const content = JSON.stringify(pkgJson, null, 2) + "\n";
187
+ await writeFile(pkgPath, content, "utf8");
188
+ }
189
+ async function findPackageJsons(packagesDir, packagePattern) {
190
+ const packageJsons = [];
191
+ let entries;
192
+ try {
193
+ entries = await readdir(packagesDir, { withFileTypes: true });
194
+ }
195
+ catch {
196
+ return packageJsons;
197
+ }
198
+ const regex = new RegExp(packagePattern);
199
+ for (const entry of entries) {
200
+ if (!entry.isDirectory())
201
+ continue;
202
+ const pkgPath = join(packagesDir, entry.name, "package.json");
203
+ try {
204
+ const pkgJson = await readPackageJson(pkgPath);
205
+ const pkgName = pkgJson["name"];
206
+ if (pkgName && regex.test(pkgName)) {
207
+ packageJsons.push({ path: pkgPath, name: pkgName, json: pkgJson });
208
+ }
209
+ }
210
+ catch {
211
+ continue;
212
+ }
213
+ }
214
+ return packageJsons;
215
+ }
216
+ function printHelp() {
217
+ console.log(`Usage: comity-normalize-package-json [options]
218
+
219
+ Options:
220
+ --packages-dir <dir> Directory containing packages (default: packages)
221
+ --package-pattern <re> Regex pattern for package names (default: ^@comity/)
222
+ --repo-root <dir> Repository root (default: auto-detected)
223
+ --check Check mode - exit with code 1 if changes needed
224
+ --help Show this help
225
+
226
+ Exit codes:
227
+ 0 - Success (no changes needed in check mode, or changes applied)
228
+ 1 - Changes needed (check mode) or error`);
229
+ }
230
+ async function main() {
231
+ const args = process.argv.slice(2);
232
+ if (args.includes("--help") || args.includes("-h")) {
233
+ printHelp();
234
+ process.exit(0);
235
+ }
236
+ const checkMode = args.includes("--check");
237
+ let packagesDir = "packages";
238
+ const packagesDirIndex = args.indexOf("--packages-dir");
239
+ if (packagesDirIndex !== -1 && packagesDirIndex + 1 < args.length) {
240
+ const val = args[packagesDirIndex + 1];
241
+ if (val)
242
+ packagesDir = val;
243
+ }
244
+ let packagePattern = "^@comity/";
245
+ const packagePatternIndex = args.indexOf("--package-pattern");
246
+ if (packagePatternIndex !== -1 && packagePatternIndex + 1 < args.length) {
247
+ const val = args[packagePatternIndex + 1];
248
+ if (val)
249
+ packagePattern = val;
250
+ }
251
+ let repoRoot = process.cwd();
252
+ const repoRootIndex = args.indexOf("--repo-root");
253
+ if (repoRootIndex !== -1 && repoRootIndex + 1 < args.length) {
254
+ const val = args[repoRootIndex + 1];
255
+ if (val)
256
+ repoRoot = resolve(val);
257
+ }
258
+ const resolvedPackagesDir = resolve(repoRoot, packagesDir);
259
+ const packageJsons = await findPackageJsons(resolvedPackagesDir, packagePattern);
260
+ let hasChanges = false;
261
+ const changedFiles = [];
262
+ for (const { path, name, json } of packageJsons) {
263
+ const normalized = normalizePackageJson(json);
264
+ const originalContent = JSON.stringify(json, null, 2) + "\n";
265
+ const normalizedContent = JSON.stringify(normalized, null, 2) + "\n";
266
+ if (originalContent !== normalizedContent) {
267
+ hasChanges = true;
268
+ changedFiles.push(name);
269
+ if (!checkMode) {
270
+ await writePackageJson(path, normalized);
271
+ console.log(`Normalized: ${name}`);
272
+ }
273
+ else {
274
+ console.log(`Would normalize: ${name}`);
275
+ }
276
+ }
277
+ }
278
+ if (checkMode) {
279
+ if (hasChanges) {
280
+ console.log(`\n${changedFiles.length} package.json file(s) would be changed:`);
281
+ for (const name of changedFiles) {
282
+ console.log(` - ${name}`);
283
+ }
284
+ process.exit(1);
285
+ }
286
+ else {
287
+ console.log("All package.json files are already normalized.");
288
+ process.exit(0);
289
+ }
290
+ }
291
+ else {
292
+ if (hasChanges) {
293
+ console.log(`\nNormalized ${changedFiles.length} package.json file(s).`);
294
+ }
295
+ else {
296
+ console.log("All package.json files are already normalized.");
297
+ }
298
+ }
299
+ }
300
+ main().catch((error) => {
301
+ console.error(error);
302
+ process.exit(1);
303
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @comity-dev/package-tools — Comity package metadata tooling.
3
+ *
4
+ * This package provides:
5
+ * - `comity-normalize-exports` binary for normalizing TypeScript export declarations
6
+ * - `comity-normalize-package-json` binary for normalizing package.json key order
7
+ *
8
+ * The CLI entry points are at `src/bin/comity-normalize-exports.ts` and `src/bin/comity-normalize-package-json.ts`.
9
+ */
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ /**
3
+ * @comity-dev/package-tools — Comity package metadata tooling.
4
+ *
5
+ * This package provides:
6
+ * - `comity-normalize-exports` binary for normalizing TypeScript export declarations
7
+ * - `comity-normalize-package-json` binary for normalizing package.json key order
8
+ *
9
+ * The CLI entry points are at `src/bin/comity-normalize-exports.ts` and `src/bin/comity-normalize-package-json.ts`.
10
+ */
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@comity-dev/package-tools",
3
+ "version": "0.1.0",
4
+ "description": "Comity package metadata tooling (export normalization, package.json normalization). Development tooling.",
5
+ "type": "module",
6
+ "private": false,
7
+ "license": "MIT",
8
+ "comity": {
9
+ "layer": "dev-tooling"
10
+ },
11
+ "engines": {
12
+ "node": ">=24.0.0"
13
+ },
14
+ "bin": {
15
+ "comity-normalize-exports": "./dist/bin/comity-normalize-exports.js",
16
+ "comity-normalize-package-json": "./dist/bin/comity-normalize-package-json.js"
17
+ },
18
+ "main": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "./dist"
28
+ ],
29
+ "dependencies": {
30
+ "typescript": "^5.9.3"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^24.13.3",
34
+ "typescript": "^5.9.3"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc -p tsconfig.json",
38
+ "test": "vitest run"
39
+ }
40
+ }