@regardio/dev 1.13.8 → 1.14.3
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 +3 -3
- package/dist/bin/exec/clean.d.ts +3 -0
- package/dist/bin/exec/clean.d.ts.map +1 -0
- package/dist/bin/exec/clean.js +25 -0
- package/dist/bin/exec/clean.test.d.ts +2 -0
- package/dist/bin/exec/clean.test.d.ts.map +1 -0
- package/dist/bin/exec/clean.test.js +45 -0
- package/dist/bin/exec/husky.d.ts +3 -0
- package/dist/bin/exec/husky.d.ts.map +1 -0
- package/dist/bin/exec/p.d.ts +3 -0
- package/dist/bin/exec/p.d.ts.map +1 -0
- package/dist/bin/exec/s.d.ts +3 -0
- package/dist/bin/exec/s.d.ts.map +1 -0
- package/dist/bin/exec/ts.d.ts +3 -0
- package/dist/bin/exec/ts.d.ts.map +1 -0
- package/dist/bin/exec/ts.js +36 -0
- package/dist/bin/exec/ts.test.d.ts +2 -0
- package/dist/bin/exec/ts.test.d.ts.map +1 -0
- package/dist/bin/exec/ts.test.js +39 -0
- package/dist/bin/exec/tsc.d.ts +3 -0
- package/dist/bin/exec/tsc.d.ts.map +1 -0
- package/dist/bin/flow/hotfix.d.ts +3 -0
- package/dist/bin/flow/hotfix.d.ts.map +1 -0
- package/dist/bin/flow/hotfix.js +116 -0
- package/dist/bin/flow/release.d.ts +3 -0
- package/dist/bin/flow/release.d.ts.map +1 -0
- package/dist/bin/flow/release.js +68 -0
- package/dist/bin/flow/ship.d.ts +3 -0
- package/dist/bin/flow/ship.d.ts.map +1 -0
- package/dist/bin/flow/ship.js +104 -0
- package/dist/bin/flow/utils.d.ts +9 -0
- package/dist/bin/flow/utils.d.ts.map +1 -0
- package/dist/bin/flow/utils.js +63 -0
- package/dist/bin/flow/utils.test.d.ts +2 -0
- package/dist/bin/flow/utils.test.d.ts.map +1 -0
- package/dist/bin/flow/utils.test.js +127 -0
- package/dist/bin/lint/biome.d.ts +3 -0
- package/dist/bin/lint/biome.d.ts.map +1 -0
- package/dist/bin/lint/commit.d.ts +3 -0
- package/dist/bin/lint/commit.d.ts.map +1 -0
- package/dist/bin/lint/md.d.ts +3 -0
- package/dist/bin/lint/md.d.ts.map +1 -0
- package/dist/bin/lint/package.d.ts +4 -0
- package/dist/bin/lint/package.d.ts.map +1 -0
- package/dist/bin/lint/package.js +81 -0
- package/dist/bin/lint/package.test.d.ts +2 -0
- package/dist/bin/lint/package.test.d.ts.map +1 -0
- package/dist/bin/lint/package.test.js +65 -0
- package/package.json +21 -22
- package/src/bin/exec/clean.test.ts +63 -0
- package/src/bin/exec/clean.ts +36 -0
- package/src/bin/exec/ts.test.ts +54 -0
- package/src/bin/exec/ts.ts +52 -0
- package/src/bin/flow/hotfix.ts +210 -0
- package/src/bin/flow/release.ts +130 -0
- package/src/bin/flow/ship.ts +215 -0
- package/src/bin/flow/utils.test.ts +178 -0
- package/src/bin/flow/utils.ts +109 -0
- package/src/bin/lint/package.test.ts +83 -0
- package/src/bin/lint/package.ts +108 -0
- package/src/templates/release.yml +23 -17
- package/dist/bin/exec-clean.d.ts +0 -3
- package/dist/bin/exec-clean.d.ts.map +0 -1
- package/dist/bin/exec-clean.js +0 -18
- package/dist/bin/exec-husky.d.ts +0 -3
- package/dist/bin/exec-husky.d.ts.map +0 -1
- package/dist/bin/exec-p.d.ts +0 -3
- package/dist/bin/exec-p.d.ts.map +0 -1
- package/dist/bin/exec-s.d.ts +0 -3
- package/dist/bin/exec-s.d.ts.map +0 -1
- package/dist/bin/exec-ts.d.ts +0 -3
- package/dist/bin/exec-ts.d.ts.map +0 -1
- package/dist/bin/exec-ts.js +0 -28
- package/dist/bin/exec-tsc.d.ts +0 -3
- package/dist/bin/exec-tsc.d.ts.map +0 -1
- package/dist/bin/flow-changeset.d.ts +0 -3
- package/dist/bin/flow-changeset.d.ts.map +0 -1
- package/dist/bin/flow-changeset.js +0 -18
- package/dist/bin/flow-release.d.ts +0 -3
- package/dist/bin/flow-release.d.ts.map +0 -1
- package/dist/bin/flow-release.js +0 -115
- package/dist/bin/lint-biome.d.ts +0 -3
- package/dist/bin/lint-biome.d.ts.map +0 -1
- package/dist/bin/lint-commit.d.ts +0 -3
- package/dist/bin/lint-commit.d.ts.map +0 -1
- package/dist/bin/lint-md.d.ts +0 -3
- package/dist/bin/lint-md.d.ts.map +0 -1
- package/dist/bin/lint-package.d.ts +0 -3
- package/dist/bin/lint-package.d.ts.map +0 -1
- package/dist/bin/lint-package.js +0 -86
- package/dist/bin/lint-package.test.d.ts +0 -2
- package/dist/bin/lint-package.test.d.ts.map +0 -1
- package/dist/bin/lint-package.test.js +0 -111
- package/src/bin/exec-clean.ts +0 -24
- package/src/bin/exec-ts.ts +0 -39
- package/src/bin/flow-changeset.ts +0 -23
- package/src/bin/flow-release.ts +0 -185
- package/src/bin/lint-package.test.ts +0 -140
- package/src/bin/lint-package.ts +0 -114
- /package/dist/bin/{exec-husky.js → exec/husky.js} +0 -0
- /package/dist/bin/{exec-p.js → exec/p.js} +0 -0
- /package/dist/bin/{exec-s.js → exec/s.js} +0 -0
- /package/dist/bin/{exec-tsc.js → exec/tsc.js} +0 -0
- /package/dist/bin/{lint-biome.js → lint/biome.js} +0 -0
- /package/dist/bin/{lint-commit.js → lint/commit.js} +0 -0
- /package/dist/bin/{lint-md.js → lint/md.js} +0 -0
- /package/src/bin/{exec-husky.ts → exec/husky.ts} +0 -0
- /package/src/bin/{exec-p.ts → exec/p.ts} +0 -0
- /package/src/bin/{exec-s.ts → exec/s.ts} +0 -0
- /package/src/bin/{exec-tsc.ts → exec/tsc.ts} +0 -0
- /package/src/bin/{lint-biome.ts → lint/biome.ts} +0 -0
- /package/src/bin/{lint-commit.ts → lint/commit.ts} +0 -0
- /package/src/bin/{lint-md.ts → lint/md.ts} +0 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { bumpVersion, confirm, insertChangelog } from './utils.js';
|
|
6
|
+
describe('bumpVersion', () => {
|
|
7
|
+
it('bumps patch', () => {
|
|
8
|
+
expect(bumpVersion('1.2.3', 'patch')).toBe('1.2.4');
|
|
9
|
+
});
|
|
10
|
+
it('bumps minor and resets patch', () => {
|
|
11
|
+
expect(bumpVersion('1.2.3', 'minor')).toBe('1.3.0');
|
|
12
|
+
});
|
|
13
|
+
it('bumps major and resets minor + patch', () => {
|
|
14
|
+
expect(bumpVersion('1.2.3', 'major')).toBe('2.0.0');
|
|
15
|
+
});
|
|
16
|
+
it('handles zero components', () => {
|
|
17
|
+
expect(bumpVersion('0.0.0', 'patch')).toBe('0.0.1');
|
|
18
|
+
expect(bumpVersion('0.0.0', 'minor')).toBe('0.1.0');
|
|
19
|
+
expect(bumpVersion('0.0.0', 'major')).toBe('1.0.0');
|
|
20
|
+
});
|
|
21
|
+
it('defaults to patch for unknown bump type', () => {
|
|
22
|
+
expect(bumpVersion('1.2.3', 'unknown')).toBe('1.2.4');
|
|
23
|
+
});
|
|
24
|
+
it('throws for invalid semver', () => {
|
|
25
|
+
expect(() => bumpVersion('not-semver', 'patch')).toThrow('Invalid semver');
|
|
26
|
+
expect(() => bumpVersion('1.2', 'patch')).toThrow('Invalid semver');
|
|
27
|
+
expect(() => bumpVersion('1.2.x', 'patch')).toThrow('Invalid semver');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe('insertChangelog', () => {
|
|
31
|
+
let tmpDir;
|
|
32
|
+
let changelogPath;
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
tmpDir = join(tmpdir(), `flow-utils-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
35
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
36
|
+
changelogPath = join(tmpDir, 'CHANGELOG.md');
|
|
37
|
+
});
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
rmSync(tmpDir, { force: true, recursive: true });
|
|
40
|
+
});
|
|
41
|
+
it('creates a new file when none exists', () => {
|
|
42
|
+
insertChangelog(changelogPath, '## [1.0.0] - 2025-01-01\n\n- initial release\n');
|
|
43
|
+
expect(existsSync(changelogPath)).toBe(true);
|
|
44
|
+
const content = readFileSync(changelogPath, 'utf-8');
|
|
45
|
+
expect(content).toContain('# Changelog');
|
|
46
|
+
expect(content).toContain('## [1.0.0] - 2025-01-01');
|
|
47
|
+
});
|
|
48
|
+
it('inserts before the first existing ## section', () => {
|
|
49
|
+
writeFileSync(changelogPath, '# Changelog\n\n## [1.0.0] - 2025-01-01\n\n- old entry\n');
|
|
50
|
+
insertChangelog(changelogPath, '## [1.1.0] - 2025-02-01\n\n- new entry\n');
|
|
51
|
+
const content = readFileSync(changelogPath, 'utf-8');
|
|
52
|
+
const newIdx = content.indexOf('## [1.1.0]');
|
|
53
|
+
const oldIdx = content.indexOf('## [1.0.0]');
|
|
54
|
+
expect(newIdx).toBeLessThan(oldIdx);
|
|
55
|
+
});
|
|
56
|
+
it('appends when no ## section exists yet', () => {
|
|
57
|
+
writeFileSync(changelogPath, '# Changelog\n');
|
|
58
|
+
insertChangelog(changelogPath, '## [1.0.0] - 2025-01-01\n\n- initial\n');
|
|
59
|
+
const content = readFileSync(changelogPath, 'utf-8');
|
|
60
|
+
expect(content).toContain('## [1.0.0]');
|
|
61
|
+
});
|
|
62
|
+
it('preserves existing entries when inserting', () => {
|
|
63
|
+
writeFileSync(changelogPath, '# Changelog\n\n## [1.0.0] - 2025-01-01\n\n- old entry\n');
|
|
64
|
+
insertChangelog(changelogPath, '## [1.1.0] - 2025-02-01\n\n- new entry\n');
|
|
65
|
+
const content = readFileSync(changelogPath, 'utf-8');
|
|
66
|
+
expect(content).toContain('## [1.0.0]');
|
|
67
|
+
expect(content).toContain('- old entry');
|
|
68
|
+
expect(content).toContain('## [1.1.0]');
|
|
69
|
+
expect(content).toContain('- new entry');
|
|
70
|
+
});
|
|
71
|
+
it('appends when file exists but has no title line', () => {
|
|
72
|
+
writeFileSync(changelogPath, '## [1.0.0] - 2025-01-01\n\n- old entry\n');
|
|
73
|
+
insertChangelog(changelogPath, '## [1.1.0] - 2025-02-01\n\n- new entry\n');
|
|
74
|
+
const content = readFileSync(changelogPath, 'utf-8');
|
|
75
|
+
expect(content).toContain('## [1.0.0]');
|
|
76
|
+
expect(content).toContain('## [1.1.0]');
|
|
77
|
+
});
|
|
78
|
+
it('handles multiple existing entries in the correct order', () => {
|
|
79
|
+
writeFileSync(changelogPath, '# Changelog\n\n## [1.1.0] - 2025-02-01\n\n- second\n\n## [1.0.0] - 2025-01-01\n\n- first\n');
|
|
80
|
+
insertChangelog(changelogPath, '## [1.2.0] - 2025-03-01\n\n- third\n');
|
|
81
|
+
const content = readFileSync(changelogPath, 'utf-8');
|
|
82
|
+
const idx120 = content.indexOf('## [1.2.0]');
|
|
83
|
+
const idx110 = content.indexOf('## [1.1.0]');
|
|
84
|
+
const idx100 = content.indexOf('## [1.0.0]');
|
|
85
|
+
expect(idx120).toBeLessThan(idx110);
|
|
86
|
+
expect(idx110).toBeLessThan(idx100);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('confirm', () => {
|
|
90
|
+
let tmpDir;
|
|
91
|
+
let inputFile;
|
|
92
|
+
beforeEach(() => {
|
|
93
|
+
tmpDir = join(tmpdir(), `confirm-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
94
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
95
|
+
inputFile = join(tmpDir, 'input');
|
|
96
|
+
vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
97
|
+
});
|
|
98
|
+
afterEach(() => {
|
|
99
|
+
rmSync(tmpDir, { force: true, recursive: true });
|
|
100
|
+
vi.restoreAllMocks();
|
|
101
|
+
});
|
|
102
|
+
it('returns true for "y"', () => {
|
|
103
|
+
writeFileSync(inputFile, 'y\n');
|
|
104
|
+
expect(confirm('Continue?', inputFile)).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
it('returns true for "Y"', () => {
|
|
107
|
+
writeFileSync(inputFile, 'Y\n');
|
|
108
|
+
expect(confirm('Continue?', inputFile)).toBe(true);
|
|
109
|
+
});
|
|
110
|
+
it('returns false for "n"', () => {
|
|
111
|
+
writeFileSync(inputFile, 'n\n');
|
|
112
|
+
expect(confirm('Continue?', inputFile)).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
it('returns false for empty input', () => {
|
|
115
|
+
writeFileSync(inputFile, '\n');
|
|
116
|
+
expect(confirm('Continue?', inputFile)).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
it('returns false for any other input', () => {
|
|
119
|
+
writeFileSync(inputFile, 'yes\n');
|
|
120
|
+
expect(confirm('Continue?', inputFile)).toBe(false);
|
|
121
|
+
});
|
|
122
|
+
it('writes the prompt to stdout', () => {
|
|
123
|
+
writeFileSync(inputFile, 'y\n');
|
|
124
|
+
confirm('Ship it?', inputFile);
|
|
125
|
+
expect(process.stdout.write).toHaveBeenCalledWith('Ship it? (y/N) ');
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"biome.d.ts","sourceRoot":"","sources":["../../../src/bin/lint/biome.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../../src/bin/lint/commit.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"md.d.ts","sourceRoot":"","sources":["../../../src/bin/lint/md.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package.d.ts","sourceRoot":"","sources":["../../../src/bin/lint/package.ts"],"names":[],"mappings":";AAcA,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuBvF;AAMD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAiBvE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { dirname, join, resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
export function reorderConditions(obj) {
|
|
7
|
+
if (typeof obj !== 'object' || obj === null)
|
|
8
|
+
return obj;
|
|
9
|
+
const processed = {};
|
|
10
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
11
|
+
processed[key] =
|
|
12
|
+
typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
13
|
+
? reorderConditions(value)
|
|
14
|
+
: value;
|
|
15
|
+
}
|
|
16
|
+
if ('types' in processed && 'default' in processed) {
|
|
17
|
+
const keys = Object.keys(processed);
|
|
18
|
+
if (keys.indexOf('default') < keys.indexOf('types')) {
|
|
19
|
+
const reordered = { types: processed.types };
|
|
20
|
+
for (const key of keys) {
|
|
21
|
+
if (key !== 'types')
|
|
22
|
+
reordered[key] = processed[key];
|
|
23
|
+
}
|
|
24
|
+
return reordered;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return processed;
|
|
28
|
+
}
|
|
29
|
+
export function fixExportsOrder(filePath, fix) {
|
|
30
|
+
const fullPath = resolve(process.cwd(), filePath);
|
|
31
|
+
if (!existsSync(fullPath))
|
|
32
|
+
return false;
|
|
33
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
34
|
+
const pkg = JSON.parse(content);
|
|
35
|
+
if (!pkg.exports || typeof pkg.exports !== 'object')
|
|
36
|
+
return false;
|
|
37
|
+
const fixed = reorderConditions(pkg.exports);
|
|
38
|
+
const changed = JSON.stringify(fixed) !== JSON.stringify(pkg.exports);
|
|
39
|
+
if (changed && fix) {
|
|
40
|
+
writeFileSync(fullPath, `${JSON.stringify({ ...pkg, exports: fixed }, null, 2)}\n`);
|
|
41
|
+
}
|
|
42
|
+
return changed;
|
|
43
|
+
}
|
|
44
|
+
if (fileURLToPath(import.meta.url) === resolve(process.argv[1] ?? '')) {
|
|
45
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
46
|
+
const devRoot = resolve(__dirname, '../../..');
|
|
47
|
+
const sortPkgBin = join(devRoot, 'node_modules/.bin/sort-package-json');
|
|
48
|
+
const sortPkgBinAlt = join(devRoot, 'node_modules/sort-package-json/cli.js');
|
|
49
|
+
let bin = '';
|
|
50
|
+
if (existsSync(sortPkgBin)) {
|
|
51
|
+
bin = sortPkgBin;
|
|
52
|
+
}
|
|
53
|
+
else if (existsSync(sortPkgBinAlt)) {
|
|
54
|
+
bin = `node ${sortPkgBinAlt}`;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
bin = 'npx sort-package-json';
|
|
58
|
+
}
|
|
59
|
+
const args = process.argv.slice(2);
|
|
60
|
+
const fixMode = args.includes('--fix');
|
|
61
|
+
const files = args.filter((arg) => arg !== '--fix');
|
|
62
|
+
const targets = files.length > 0 ? files : ['package.json'];
|
|
63
|
+
try {
|
|
64
|
+
const checkFlag = fixMode ? '' : '--check';
|
|
65
|
+
execSync(`${bin} ${checkFlag} ${targets.join(' ')}`.trim(), { stdio: 'inherit' });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
let hasExportsIssues = false;
|
|
71
|
+
for (const file of targets) {
|
|
72
|
+
const needsFix = fixExportsOrder(file, fixMode);
|
|
73
|
+
if (needsFix && !fixMode) {
|
|
74
|
+
console.error(`${file}: exports condition order is incorrect (types must come before default)`);
|
|
75
|
+
hasExportsIssues = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (hasExportsIssues) {
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package.test.d.ts","sourceRoot":"","sources":["../../../src/bin/lint/package.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { reorderConditions } from './package.js';
|
|
3
|
+
describe('lint-package', () => {
|
|
4
|
+
describe('reorderConditions', () => {
|
|
5
|
+
it('reorders types before default when default comes first', () => {
|
|
6
|
+
const input = {
|
|
7
|
+
'./foo': {
|
|
8
|
+
default: './dist/foo.js',
|
|
9
|
+
types: './dist/foo.d.ts',
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
const result = reorderConditions(input);
|
|
13
|
+
expect(Object.keys(result['./foo'])).toEqual(['types', 'default']);
|
|
14
|
+
});
|
|
15
|
+
it('does not modify when types already comes before default', () => {
|
|
16
|
+
const input = {
|
|
17
|
+
'./foo': {
|
|
18
|
+
default: './dist/foo.js',
|
|
19
|
+
types: './dist/foo.d.ts',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const result = reorderConditions(input);
|
|
23
|
+
expect(Object.keys(result['./foo'])).toEqual(['types', 'default']);
|
|
24
|
+
});
|
|
25
|
+
it('handles multiple exports with mixed order', () => {
|
|
26
|
+
const input = {
|
|
27
|
+
'./a': { default: './dist/a.js', types: './dist/a.d.ts' },
|
|
28
|
+
'./b': { default: './dist/b.js', types: './dist/b.d.ts' },
|
|
29
|
+
};
|
|
30
|
+
const result = reorderConditions(input);
|
|
31
|
+
expect(Object.keys(result['./a'])[0]).toBe('types');
|
|
32
|
+
expect(Object.keys(result['./b'])[0]).toBe('types');
|
|
33
|
+
});
|
|
34
|
+
it('preserves other keys after types', () => {
|
|
35
|
+
const input = {
|
|
36
|
+
'./foo': {
|
|
37
|
+
default: './dist/foo.js',
|
|
38
|
+
import: './dist/foo.mjs',
|
|
39
|
+
require: './dist/foo.cjs',
|
|
40
|
+
types: './dist/foo.d.ts',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
const result = reorderConditions(input);
|
|
44
|
+
const keys = Object.keys(result['./foo']);
|
|
45
|
+
expect(keys[0]).toBe('types');
|
|
46
|
+
expect(keys.slice(1)).toEqual(['default', 'import', 'require']);
|
|
47
|
+
});
|
|
48
|
+
it('handles exports without types or default', () => {
|
|
49
|
+
const input = { './styles.css': './dist/styles.css' };
|
|
50
|
+
expect(reorderConditions(input)).toEqual(input);
|
|
51
|
+
});
|
|
52
|
+
it('handles deeply nested condition objects', () => {
|
|
53
|
+
const input = {
|
|
54
|
+
'./foo': {
|
|
55
|
+
browser: { default: './dist/foo.browser.js', types: './dist/foo.browser.d.ts' },
|
|
56
|
+
node: { default: './dist/foo.node.js', types: './dist/foo.node.d.ts' },
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
const result = reorderConditions(input);
|
|
60
|
+
const foo = result['./foo'];
|
|
61
|
+
expect(Object.keys(foo.node)[0]).toBe('types');
|
|
62
|
+
expect(Object.keys(foo.browser)[0]).toBe('types');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://www.schemastore.org/package.json",
|
|
3
3
|
"name": "@regardio/dev",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.14.3",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Regardio developer tooling for testing, linting, and build workflows",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"biome",
|
|
9
|
-
"changesets",
|
|
10
9
|
"commitlint",
|
|
11
10
|
"dev",
|
|
12
11
|
"husky",
|
|
@@ -56,43 +55,43 @@
|
|
|
56
55
|
}
|
|
57
56
|
},
|
|
58
57
|
"bin": {
|
|
59
|
-
"exec-clean": "dist/bin/exec
|
|
60
|
-
"exec-husky": "dist/bin/exec
|
|
61
|
-
"exec-p": "dist/bin/exec
|
|
62
|
-
"exec-s": "dist/bin/exec
|
|
63
|
-
"exec-ts": "dist/bin/exec
|
|
64
|
-
"exec-tsc": "dist/bin/exec
|
|
65
|
-
"flow-
|
|
66
|
-
"flow-release": "dist/bin/flow
|
|
67
|
-
"
|
|
68
|
-
"lint-
|
|
69
|
-
"lint-
|
|
70
|
-
"lint-
|
|
58
|
+
"exec-clean": "dist/bin/exec/clean.js",
|
|
59
|
+
"exec-husky": "dist/bin/exec/husky.js",
|
|
60
|
+
"exec-p": "dist/bin/exec/p.js",
|
|
61
|
+
"exec-s": "dist/bin/exec/s.js",
|
|
62
|
+
"exec-ts": "dist/bin/exec/ts.js",
|
|
63
|
+
"exec-tsc": "dist/bin/exec/tsc.js",
|
|
64
|
+
"flow-hotfix": "dist/bin/flow/hotfix.js",
|
|
65
|
+
"flow-release": "dist/bin/flow/release.js",
|
|
66
|
+
"flow-ship": "dist/bin/flow/ship.js",
|
|
67
|
+
"lint-biome": "dist/bin/lint/biome.js",
|
|
68
|
+
"lint-commit": "dist/bin/lint/commit.js",
|
|
69
|
+
"lint-md": "dist/bin/lint/md.js",
|
|
70
|
+
"lint-package": "dist/bin/lint/package.js"
|
|
71
71
|
},
|
|
72
72
|
"files": ["dist", "src"],
|
|
73
73
|
"scripts": {
|
|
74
74
|
"build": "tsc -p tsconfig.build.json",
|
|
75
|
-
"clean": "tsx src/bin/exec
|
|
75
|
+
"clean": "tsx src/bin/exec/clean.ts .turbo dist",
|
|
76
76
|
"fix": "run-s fix:pkg fix:md fix:biome",
|
|
77
77
|
"fix:biome": "biome check --write --unsafe .",
|
|
78
78
|
"fix:md": "markdownlint-cli2 --fix",
|
|
79
|
-
"fix:pkg": "tsx src/bin/lint
|
|
79
|
+
"fix:pkg": "tsx src/bin/lint/package.ts --fix",
|
|
80
|
+
"flow:hotfix": "tsx src/bin/flow/hotfix.ts",
|
|
81
|
+
"flow:release": "tsx src/bin/flow/release.ts",
|
|
82
|
+
"flow:ship": "tsx src/bin/flow/ship.ts",
|
|
80
83
|
"lint": "run-s lint:md lint:biome",
|
|
81
84
|
"lint:biome": "biome check .",
|
|
82
85
|
"lint:md": "markdownlint-cli2",
|
|
83
|
-
"lint:pkg": "tsx src/bin/lint
|
|
86
|
+
"lint:pkg": "tsx src/bin/lint/package.ts",
|
|
84
87
|
"prepare": "husky",
|
|
85
|
-
"release": "tsx src/bin/flow-release.ts",
|
|
86
88
|
"report": "vitest run --coverage",
|
|
87
89
|
"test": "run-p test:*",
|
|
88
90
|
"test:unit": "vitest run",
|
|
89
|
-
"typecheck": "tsc --noEmit"
|
|
90
|
-
"version": "tsx src/bin/flow-changeset.ts version"
|
|
91
|
+
"typecheck": "tsc --noEmit"
|
|
91
92
|
},
|
|
92
93
|
"dependencies": {
|
|
93
94
|
"@biomejs/biome": "2.4.4",
|
|
94
|
-
"@changesets/changelog-github": "0.5.2",
|
|
95
|
-
"@changesets/cli": "2.29.8",
|
|
96
95
|
"@commitlint/cli": "20.4.2",
|
|
97
96
|
"@commitlint/config-conventional": "20.4.2",
|
|
98
97
|
"@playwright/test": "1.58.2",
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { resolveRimrafBin } from './clean.js';
|
|
6
|
+
|
|
7
|
+
function makeRequire(pkgPath: string, pkg: unknown): NodeRequire {
|
|
8
|
+
const req = (id: string): unknown => (id === pkgPath ? pkg : undefined);
|
|
9
|
+
req.resolve = (_id: string) => pkgPath;
|
|
10
|
+
return req as unknown as NodeRequire;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('resolveRimrafBin', () => {
|
|
14
|
+
it('resolves when bin is a plain string', () => {
|
|
15
|
+
const pkgPath = '/node_modules/rimraf/package.json';
|
|
16
|
+
const req = makeRequire(pkgPath, { bin: './dist/esm/bin.js' });
|
|
17
|
+
|
|
18
|
+
const result = resolveRimrafBin(req);
|
|
19
|
+
|
|
20
|
+
expect(result).toBe(path.join('/node_modules/rimraf', 'dist/esm/bin.js'));
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('strips leading ./ from the bin path', () => {
|
|
24
|
+
const pkgPath = '/node_modules/rimraf/package.json';
|
|
25
|
+
const req = makeRequire(pkgPath, { bin: './bin/rimraf' });
|
|
26
|
+
|
|
27
|
+
const result = resolveRimrafBin(req);
|
|
28
|
+
|
|
29
|
+
expect(result).toBe(path.join('/node_modules/rimraf', 'bin/rimraf'));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('resolves when bin is an object with a rimraf key', () => {
|
|
33
|
+
const pkgPath = '/node_modules/rimraf/package.json';
|
|
34
|
+
const req = makeRequire(pkgPath, { bin: { rimraf: './dist/esm/bin.js' } });
|
|
35
|
+
|
|
36
|
+
const result = resolveRimrafBin(req);
|
|
37
|
+
|
|
38
|
+
expect(result).toBe(path.join('/node_modules/rimraf', 'dist/esm/bin.js'));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('returns null when bin field is missing', () => {
|
|
42
|
+
const pkgPath = '/node_modules/rimraf/package.json';
|
|
43
|
+
const req = makeRequire(pkgPath, {});
|
|
44
|
+
|
|
45
|
+
expect(resolveRimrafBin(req)).toBeNull();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('returns null when bin object has no rimraf key', () => {
|
|
49
|
+
const pkgPath = '/node_modules/rimraf/package.json';
|
|
50
|
+
const req = makeRequire(pkgPath, { bin: { other: './dist/other.js' } });
|
|
51
|
+
|
|
52
|
+
expect(resolveRimrafBin(req)).toBeNull();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('resolves against the real rimraf package', () => {
|
|
56
|
+
const req = createRequire(import.meta.url);
|
|
57
|
+
|
|
58
|
+
const result = resolveRimrafBin(req);
|
|
59
|
+
|
|
60
|
+
expect(result).not.toBeNull();
|
|
61
|
+
expect(path.isAbsolute(result ?? '')).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* exec-clean: Thin wrapper around rimraf for cleaning paths.
|
|
4
|
+
* Usage: exec-clean <path> [morePaths...]
|
|
5
|
+
*/
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the absolute path to the rimraf binary from its package.json bin field.
|
|
13
|
+
* Returns the resolved path, or null if it cannot be determined.
|
|
14
|
+
*/
|
|
15
|
+
export function resolveRimrafBin(require: NodeRequire): string | null {
|
|
16
|
+
const pkgPath = require.resolve('rimraf/package.json');
|
|
17
|
+
const pkg = require(pkgPath) as { bin?: unknown };
|
|
18
|
+
const binRel =
|
|
19
|
+
typeof pkg.bin === 'string' ? pkg.bin : (pkg.bin as Record<string, string>)?.rimraf;
|
|
20
|
+
if (!binRel) return null;
|
|
21
|
+
const normalized = binRel.startsWith('./') ? binRel.slice(2) : binRel;
|
|
22
|
+
return path.join(path.dirname(pkgPath), normalized);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
26
|
+
const require = createRequire(import.meta.url);
|
|
27
|
+
const bin = resolveRimrafBin(require);
|
|
28
|
+
if (!bin) {
|
|
29
|
+
console.error('Unable to locate rimraf binary from package.json bin field');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const args = process.argv.slice(2);
|
|
34
|
+
const child = spawn(process.execPath, [bin, ...args], { stdio: 'inherit' });
|
|
35
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
36
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { resolveTsxBin } from './ts.js';
|
|
6
|
+
|
|
7
|
+
function makeRequire(pkgPath: string, pkg: unknown): NodeRequire {
|
|
8
|
+
const req = (id: string): unknown => (id === pkgPath ? pkg : undefined);
|
|
9
|
+
req.resolve = (_id: string) => pkgPath;
|
|
10
|
+
return req as unknown as NodeRequire;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('resolveTsxBin', () => {
|
|
14
|
+
it('resolves when bin is a string', () => {
|
|
15
|
+
const pkgPath = '/node_modules/tsx/package.json';
|
|
16
|
+
const req = makeRequire(pkgPath, { bin: './dist/cli.mjs' });
|
|
17
|
+
|
|
18
|
+
const result = resolveTsxBin(req);
|
|
19
|
+
|
|
20
|
+
expect(result).toBe(path.join('/node_modules/tsx', 'dist/cli.mjs'));
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('resolves when bin is an object with a tsx key', () => {
|
|
24
|
+
const pkgPath = '/node_modules/tsx/package.json';
|
|
25
|
+
const req = makeRequire(pkgPath, { bin: { tsx: './dist/cli.mjs' } });
|
|
26
|
+
|
|
27
|
+
const result = resolveTsxBin(req);
|
|
28
|
+
|
|
29
|
+
expect(result).toBe(path.join('/node_modules/tsx', 'dist/cli.mjs'));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('returns null when bin field is missing', () => {
|
|
33
|
+
const pkgPath = '/node_modules/tsx/package.json';
|
|
34
|
+
const req = makeRequire(pkgPath, {});
|
|
35
|
+
|
|
36
|
+
expect(resolveTsxBin(req)).toBeNull();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('returns null when bin object has no tsx key', () => {
|
|
40
|
+
const pkgPath = '/node_modules/tsx/package.json';
|
|
41
|
+
const req = makeRequire(pkgPath, { bin: { other: './dist/other.js' } });
|
|
42
|
+
|
|
43
|
+
expect(resolveTsxBin(req)).toBeNull();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('resolves against the real tsx package', () => {
|
|
47
|
+
const req = createRequire(import.meta.url);
|
|
48
|
+
|
|
49
|
+
const result = resolveTsxBin(req);
|
|
50
|
+
|
|
51
|
+
expect(result).not.toBeNull();
|
|
52
|
+
expect(path.isAbsolute(result ?? '')).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* exec-ts: Run a local TypeScript file via tsx with TS support.
|
|
4
|
+
* Usage: exec-ts path/to/script.ts [args...]
|
|
5
|
+
*/
|
|
6
|
+
import { type SpawnOptions, spawn } from 'node:child_process';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the absolute path to the tsx binary from its package.json bin field.
|
|
13
|
+
* Returns the resolved path, or null if it cannot be determined.
|
|
14
|
+
*/
|
|
15
|
+
export function resolveTsxBin(require: NodeRequire): string | null {
|
|
16
|
+
const pkgPath = require.resolve('tsx/package.json');
|
|
17
|
+
const pkg = require(pkgPath) as { bin?: unknown };
|
|
18
|
+
const binRel = pkg.bin;
|
|
19
|
+
const binEntry: string | undefined =
|
|
20
|
+
typeof binRel === 'string'
|
|
21
|
+
? binRel
|
|
22
|
+
: typeof binRel === 'object' && binRel !== null && 'tsx' in binRel
|
|
23
|
+
? (binRel as Record<string, string>).tsx
|
|
24
|
+
: undefined;
|
|
25
|
+
if (!binEntry) return null;
|
|
26
|
+
return path.join(path.dirname(pkgPath), binEntry);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// CLI entry point — only runs when executed directly
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1] ?? '')) {
|
|
33
|
+
const args = process.argv.slice(2);
|
|
34
|
+
if (args.length === 0) {
|
|
35
|
+
console.error('Usage: exec-ts <script.ts> [args...]');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const [scriptArg, ...rest] = args;
|
|
40
|
+
const script = scriptArg ?? '';
|
|
41
|
+
|
|
42
|
+
const require = createRequire(import.meta.url);
|
|
43
|
+
const bin = resolveTsxBin(require);
|
|
44
|
+
if (!bin) {
|
|
45
|
+
console.error('Unable to locate tsx binary from package.json bin field');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const spawnOptions: SpawnOptions = { stdio: 'inherit' };
|
|
50
|
+
const child = spawn(process.execPath, [bin, script, ...rest], spawnOptions);
|
|
51
|
+
child.on('exit', (code: number | null) => process.exit(code ?? 0));
|
|
52
|
+
}
|