ras-stack 0.38.3 → 0.39.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/README.md +1 -1
- package/dist/policy/cli.js +7 -11
- package/dist/policy/cli.js.map +1 -1
- package/dist/policy/index.d.ts +0 -16
- package/dist/policy/index.js +2 -167
- package/dist/policy/index.js.map +1 -1
- package/dist/policy/init.d.ts +5 -2
- package/dist/policy/init.js +5 -10
- package/dist/policy/init.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -85,7 +85,7 @@ Start with the narrowest public entrypoint that owns the repeated mechanic:
|
|
|
85
85
|
| Email, uploads, and production assets | `ras-stack/email`, `ras-stack/uploads`, `ras assets` | Templates, metadata, quotas, storage, and asset contents |
|
|
86
86
|
| Production or development realtime runtime | `ras-stack/runtime`, `ras realtime` | Images, ports, secrets, volumes, and distributed policy |
|
|
87
87
|
| Compiler, lint, CI, release, and preview mechanics | `ras-stack/config/*`, `actions/*`, `.github/workflows/*`, `ras-stack/preview/*` | Triggers, permissions, services, deployment, and verification |
|
|
88
|
-
| Generated repository policy
|
|
88
|
+
| Generated repository policy files | `ras policy` | Which policies apply and every declared override |
|
|
89
89
|
|
|
90
90
|
## Dokploy previews 🚀
|
|
91
91
|
|
package/dist/policy/cli.js
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
import { checkRepositoryPolicy,
|
|
1
|
+
import { checkRepositoryPolicy, syncRepositoryPolicy } from './index.js';
|
|
2
2
|
export async function runPolicyCli(arguments_) {
|
|
3
|
-
const [command,
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const [command, extra] = arguments_;
|
|
4
|
+
// `adoption` used to be a second argument. Failing beats quietly running a repository sync somebody did not ask for.
|
|
5
|
+
if ((command !== 'check' && command !== 'sync') || extra !== undefined) {
|
|
6
|
+
console.error('usage: ras policy <check|sync>');
|
|
6
7
|
process.exitCode = 2;
|
|
7
8
|
return;
|
|
8
9
|
}
|
|
9
|
-
const
|
|
10
|
-
const changed = adoption
|
|
11
|
-
? await syncAdoptionPolicy(process.cwd(), command === 'check' ? 'check' : 'write')
|
|
12
|
-
: command === 'check'
|
|
13
|
-
? await checkRepositoryPolicy(process.cwd())
|
|
14
|
-
: await syncRepositoryPolicy(process.cwd(), 'write');
|
|
10
|
+
const changed = command === 'check' ? await checkRepositoryPolicy(process.cwd()) : await syncRepositoryPolicy(process.cwd(), 'write');
|
|
15
11
|
if (command === 'check' && changed.length > 0) {
|
|
16
12
|
for (const message of changed)
|
|
17
13
|
console.error(message);
|
|
18
|
-
console.error(
|
|
14
|
+
console.error('run ras policy sync and commit the result');
|
|
19
15
|
process.exitCode = 1;
|
|
20
16
|
}
|
|
21
17
|
else if (command === 'sync') {
|
package/dist/policy/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/policy/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/policy/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAExE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAoB;IACrD,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,UAAU,CAAA;IACnC,qHAAqH;IACrH,IAAI,CAAC,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,MAAM,CAAC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAA;QAC/C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;QACpB,OAAM;IACR,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,qBAAqB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,oBAAoB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAA;IACrI,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,KAAK,MAAM,OAAO,IAAI,OAAO;YAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACrD,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAC1D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;IACtB,CAAC;SAAM,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QAC9B,KAAK,MAAM,IAAI,IAAI,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAA;IAC5D,CAAC;AACH,CAAC","sourcesContent":["import { checkRepositoryPolicy, syncRepositoryPolicy } from './index.js'\n\nexport async function runPolicyCli(arguments_: string[]): Promise<void> {\n const [command, extra] = arguments_\n // `adoption` used to be a second argument. Failing beats quietly running a repository sync somebody did not ask for.\n if ((command !== 'check' && command !== 'sync') || extra !== undefined) {\n console.error('usage: ras policy <check|sync>')\n process.exitCode = 2\n return\n }\n\n const changed = command === 'check' ? await checkRepositoryPolicy(process.cwd()) : await syncRepositoryPolicy(process.cwd(), 'write')\n if (command === 'check' && changed.length > 0) {\n for (const message of changed) console.error(message)\n console.error('run ras policy sync and commit the result')\n process.exitCode = 1\n } else if (command === 'sync') {\n for (const path of changed) console.log(`updated ${path}`)\n }\n}\n"]}
|
package/dist/policy/index.d.ts
CHANGED
|
@@ -7,24 +7,8 @@ export type RepositoryPolicy = {
|
|
|
7
7
|
pnpm?: false | {
|
|
8
8
|
minimumReleaseAge?: number;
|
|
9
9
|
};
|
|
10
|
-
adoption?: false | AdoptionPolicy;
|
|
11
|
-
};
|
|
12
|
-
export type AdoptionPolicy = {
|
|
13
|
-
minimumRasStackVersion?: string;
|
|
14
|
-
minimumWorkflowRasStackVersion?: string;
|
|
15
|
-
node?: string;
|
|
16
|
-
pnpm?: string;
|
|
17
|
-
just?: string;
|
|
18
|
-
requiredReferences?: string[];
|
|
19
|
-
};
|
|
20
|
-
export type AdoptionSnapshot = {
|
|
21
|
-
manifest: Record<string, unknown>;
|
|
22
|
-
files: Map<string, string>;
|
|
23
10
|
};
|
|
24
11
|
export declare function syncRepositoryPolicy(root: string, mode: 'check' | 'write'): Promise<string[]>;
|
|
25
12
|
export declare function checkRepositoryPolicy(root: string): Promise<string[]>;
|
|
26
|
-
export declare function syncAdoptionPolicy(root: string, mode: 'check' | 'write'): Promise<string[]>;
|
|
27
|
-
export declare function adoptionDrift(root: string, policy: AdoptionPolicy): Promise<string[]>;
|
|
28
|
-
export declare function adoptionSnapshotDrift(snapshot: AdoptionSnapshot, policy: AdoptionPolicy): string[];
|
|
29
13
|
export declare function renderedPolicyFiles(root: string, config: RepositoryPolicy): Promise<Map<string, string>>;
|
|
30
14
|
export {};
|
package/dist/policy/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, readFile,
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { parseDocument, stringify } from 'yaml';
|
|
4
4
|
const changesetsPolicy = {
|
|
@@ -48,67 +48,7 @@ export async function syncRepositoryPolicy(root, mode) {
|
|
|
48
48
|
}
|
|
49
49
|
export async function checkRepositoryPolicy(root) {
|
|
50
50
|
const files = await syncRepositoryPolicy(root, 'check');
|
|
51
|
-
|
|
52
|
-
return [...files.map((path) => `policy drift: ${path}`), ...(config.adoption ? await adoptionDrift(root, config.adoption) : [])];
|
|
53
|
-
}
|
|
54
|
-
export async function syncAdoptionPolicy(root, mode) {
|
|
55
|
-
const config = repositoryPolicy(await readFile(join(root, 'ras-stack.policy.json'), 'utf8'));
|
|
56
|
-
if (!config.adoption)
|
|
57
|
-
return [];
|
|
58
|
-
const files = await renderedAdoptionFiles(root, config.adoption);
|
|
59
|
-
const changed = await Promise.all([...files].map(async ([path, expected]) => {
|
|
60
|
-
const absolute = join(root, path);
|
|
61
|
-
const actual = await readFile(absolute, 'utf8');
|
|
62
|
-
if (actual === expected)
|
|
63
|
-
return undefined;
|
|
64
|
-
if (mode === 'write')
|
|
65
|
-
await writeFile(absolute, expected);
|
|
66
|
-
return path;
|
|
67
|
-
}));
|
|
68
|
-
return changed.filter((path) => path !== undefined);
|
|
69
|
-
}
|
|
70
|
-
export async function adoptionDrift(root, policy) {
|
|
71
|
-
const manifest = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
|
|
72
|
-
const files = await adoptionFiles(root);
|
|
73
|
-
return adoptionSnapshotDrift({ manifest, files }, policy);
|
|
74
|
-
}
|
|
75
|
-
export function adoptionSnapshotDrift(snapshot, policy) {
|
|
76
|
-
const drift = [];
|
|
77
|
-
const { manifest, files } = snapshot;
|
|
78
|
-
if (policy.node && manifest.engines && plainObject(manifest.engines) && manifest.engines.node !== policy.node) {
|
|
79
|
-
drift.push(`toolchain drift: package.json engines.node must be ${policy.node}`);
|
|
80
|
-
}
|
|
81
|
-
if (policy.pnpm && manifest.packageManager !== `pnpm@${policy.pnpm}`) {
|
|
82
|
-
drift.push(`toolchain drift: package.json packageManager must be pnpm@${policy.pnpm}`);
|
|
83
|
-
}
|
|
84
|
-
if (policy.minimumRasStackVersion) {
|
|
85
|
-
const dependency = dependencyVersion(manifest, 'ras-stack');
|
|
86
|
-
if (dependency && compareVersions(dependency, policy.minimumRasStackVersion) < 0) {
|
|
87
|
-
drift.push(`ras-stack drift: package.json uses ${dependency}, minimum is ${policy.minimumRasStackVersion}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const workflows = new Map([...files].filter(([path]) => path.startsWith('.github/') && /\.ya?ml$/.test(path)));
|
|
91
|
-
const workflowMinimum = policy.minimumWorkflowRasStackVersion ?? policy.minimumRasStackVersion;
|
|
92
|
-
for (const [path, source] of workflows) {
|
|
93
|
-
if (workflowMinimum) {
|
|
94
|
-
for (const match of source.matchAll(/richardsolomou\/ras-stack\/[^\s'"}]+@v(\d+\.\d+\.\d+)/g)) {
|
|
95
|
-
const version = match[1];
|
|
96
|
-
if (version && compareVersions(version, workflowMinimum) < 0) {
|
|
97
|
-
drift.push(`ras-stack drift: ${path} uses v${version}, minimum is v${workflowMinimum}`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
if (policy.just &&
|
|
103
|
-
![...workflows.values()].some((source) => source.includes(`just-version: '${policy.just}'`) || source.includes(`just-version: ${policy.just}`))) {
|
|
104
|
-
drift.push(`toolchain drift: no workflow declares just-version ${policy.just}`);
|
|
105
|
-
}
|
|
106
|
-
for (const reference of policy.requiredReferences ?? []) {
|
|
107
|
-
if (![...files.values()].some((source) => source.includes(reference))) {
|
|
108
|
-
drift.push(`shared config drift: no configuration references ${reference}`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return [...new Set(drift)];
|
|
51
|
+
return files.map((path) => `policy drift: ${path}`);
|
|
112
52
|
}
|
|
113
53
|
export async function renderedPolicyFiles(root, config) {
|
|
114
54
|
const files = new Map();
|
|
@@ -141,110 +81,8 @@ function repositoryPolicy(source) {
|
|
|
141
81
|
throw new Error('pnpm.minimumReleaseAge must be a non-negative integer');
|
|
142
82
|
}
|
|
143
83
|
}
|
|
144
|
-
const adoption = value.adoption;
|
|
145
|
-
if (adoption !== undefined && adoption !== false) {
|
|
146
|
-
if (!plainObject(adoption))
|
|
147
|
-
throw new Error('adoption policy must be false or an object');
|
|
148
|
-
for (const key of ['minimumRasStackVersion', 'minimumWorkflowRasStackVersion', 'node', 'pnpm', 'just']) {
|
|
149
|
-
if (adoption[key] !== undefined && typeof adoption[key] !== 'string')
|
|
150
|
-
throw new Error(`adoption.${key} must be a string`);
|
|
151
|
-
}
|
|
152
|
-
if (adoption.requiredReferences !== undefined && !stringArray(adoption.requiredReferences)) {
|
|
153
|
-
throw new Error('adoption.requiredReferences must be an array of strings');
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
84
|
return value;
|
|
157
85
|
}
|
|
158
|
-
function dependencyVersion(manifest, name) {
|
|
159
|
-
for (const field of ['dependencies', 'devDependencies']) {
|
|
160
|
-
const dependencies = manifest[field];
|
|
161
|
-
const value = plainObject(dependencies) ? dependencies[name] : undefined;
|
|
162
|
-
if (typeof value === 'string')
|
|
163
|
-
return /\d+\.\d+\.\d+/.exec(value)?.[0];
|
|
164
|
-
}
|
|
165
|
-
return undefined;
|
|
166
|
-
}
|
|
167
|
-
function compareVersions(left, right) {
|
|
168
|
-
const a = left.split('.').map(Number);
|
|
169
|
-
const b = right.split('.').map(Number);
|
|
170
|
-
for (let index = 0; index < 3; index += 1) {
|
|
171
|
-
if (a[index] !== b[index])
|
|
172
|
-
return (a[index] ?? 0) - (b[index] ?? 0);
|
|
173
|
-
}
|
|
174
|
-
return 0;
|
|
175
|
-
}
|
|
176
|
-
async function textFiles(directory, root = directory) {
|
|
177
|
-
const files = new Map();
|
|
178
|
-
const entries = await readdir(directory, { withFileTypes: true }).catch(() => []);
|
|
179
|
-
const results = await Promise.all(entries.map(async (entry) => {
|
|
180
|
-
const path = join(directory, entry.name);
|
|
181
|
-
if (entry.isDirectory())
|
|
182
|
-
return textFiles(path, root);
|
|
183
|
-
if (/\.ya?ml$/.test(entry.name))
|
|
184
|
-
return new Map([[path.slice(root.length + 1), await readFile(path, 'utf8')]]);
|
|
185
|
-
return new Map();
|
|
186
|
-
}));
|
|
187
|
-
for (const result of results) {
|
|
188
|
-
for (const [path, source] of result)
|
|
189
|
-
files.set(path, source);
|
|
190
|
-
}
|
|
191
|
-
return files;
|
|
192
|
-
}
|
|
193
|
-
async function adoptionFiles(root) {
|
|
194
|
-
const files = await textFiles(join(root, '.github'), root);
|
|
195
|
-
const entries = await readdir(root, { withFileTypes: true });
|
|
196
|
-
await Promise.all(entries.map(async (entry) => {
|
|
197
|
-
if (!entry.isFile() || !/^(?:ras-stack\.policy|oxlint|tsconfig(?:\.[^.]+)*)\.json$/.test(entry.name))
|
|
198
|
-
return;
|
|
199
|
-
files.set(entry.name, await readFile(join(root, entry.name), 'utf8'));
|
|
200
|
-
}));
|
|
201
|
-
return files;
|
|
202
|
-
}
|
|
203
|
-
async function renderedAdoptionFiles(root, policy) {
|
|
204
|
-
const files = new Map();
|
|
205
|
-
const manifestPath = join(root, 'package.json');
|
|
206
|
-
const manifestSource = await readFile(manifestPath, 'utf8');
|
|
207
|
-
const manifest = JSON.parse(manifestSource);
|
|
208
|
-
if (policy.node) {
|
|
209
|
-
const engines = plainObject(manifest.engines) ? manifest.engines : {};
|
|
210
|
-
manifest.engines = { ...engines, node: policy.node };
|
|
211
|
-
}
|
|
212
|
-
if (policy.pnpm)
|
|
213
|
-
manifest.packageManager = `pnpm@${policy.pnpm}`;
|
|
214
|
-
if (policy.minimumRasStackVersion) {
|
|
215
|
-
for (const field of ['dependencies', 'devDependencies']) {
|
|
216
|
-
const dependencies = manifest[field];
|
|
217
|
-
if (!plainObject(dependencies) || typeof dependencies['ras-stack'] !== 'string')
|
|
218
|
-
continue;
|
|
219
|
-
dependencies['ras-stack'] = versionAtLeast(dependencies['ras-stack'], policy.minimumRasStackVersion);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
const renderedManifest = `${JSON.stringify(manifest, null, 2)}\n`;
|
|
223
|
-
if (renderedManifest !== manifestSource)
|
|
224
|
-
files.set('package.json', renderedManifest);
|
|
225
|
-
const workflowVersion = policy.minimumWorkflowRasStackVersion ?? policy.minimumRasStackVersion;
|
|
226
|
-
const workflows = await textFiles(join(root, '.github'), root);
|
|
227
|
-
for (const [path, source] of workflows) {
|
|
228
|
-
let rendered = source;
|
|
229
|
-
if (workflowVersion) {
|
|
230
|
-
rendered = rendered.replace(/(richardsolomou\/ras-stack\/[^\s'"}]+@v)(\d+\.\d+\.\d+)/g, (reference, prefix, current) => compareVersions(current, workflowVersion) < 0 ? `${prefix}${workflowVersion}` : reference);
|
|
231
|
-
}
|
|
232
|
-
if (policy.just) {
|
|
233
|
-
rendered = rendered.replace(/(just-version:\s*)(['"]?)\d+\.\d+\.\d+\2/g, `$1$2${policy.just}$2`);
|
|
234
|
-
rendered = rendered.replace(/(richardsolomou\/ras-stack\/actions\/setup-just@[^\n]+\n(?:(?!\n\s*-\s+uses:)[\s\S]){0,300}?\n\s+version:\s*)(['"]?)\d+\.\d+\.\d+\2/g, `$1$2${policy.just}$2`);
|
|
235
|
-
}
|
|
236
|
-
if (rendered !== source)
|
|
237
|
-
files.set(path, rendered);
|
|
238
|
-
}
|
|
239
|
-
return files;
|
|
240
|
-
}
|
|
241
|
-
function versionAtLeast(current, version) {
|
|
242
|
-
const match = /^(\s*(?:\^|~|>=|>|<=|<|=)?\s*)\d+\.\d+\.\d+(.*)$/.exec(current);
|
|
243
|
-
const currentVersion = /\d+\.\d+\.\d+/.exec(current)?.[0];
|
|
244
|
-
if (currentVersion && compareVersions(currentVersion, version) >= 0)
|
|
245
|
-
return current;
|
|
246
|
-
return match ? `${match[1]}${version}${match[2]}` : version;
|
|
247
|
-
}
|
|
248
86
|
function validateSelection(name, value) {
|
|
249
87
|
if (value === undefined || typeof value === 'boolean')
|
|
250
88
|
return;
|
|
@@ -265,7 +103,4 @@ function deepMerge(base, overrides) {
|
|
|
265
103
|
function plainObject(value) {
|
|
266
104
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
267
105
|
}
|
|
268
|
-
function stringArray(value) {
|
|
269
|
-
return Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
270
|
-
}
|
|
271
106
|
//# sourceMappingURL=index.js.map
|
package/dist/policy/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { parseDocument, stringify } from 'yaml'\n\nconst changesetsPolicy = {\n $schema: 'https://unpkg.com/@changesets/config@3.1.2/schema.json',\n changelog: '@changesets/cli/changelog',\n commit: false,\n fixed: [],\n linked: [],\n access: 'public',\n baseBranch: 'main',\n updateInternalDependencies: 'patch',\n ignore: [],\n}\n\nconst dependabotPolicy = {\n version: 2,\n updates: [\n {\n 'package-ecosystem': 'npm',\n directory: '/',\n schedule: { interval: 'weekly' },\n cooldown: { 'default-days': 7 },\n groups: { 'javascript-dependencies': { patterns: ['*'] } },\n },\n {\n 'package-ecosystem': 'github-actions',\n directory: '/',\n schedule: { interval: 'weekly' },\n cooldown: { 'default-days': 7 },\n },\n ],\n}\n\ntype PolicySelection = boolean | { overrides?: Record<string, unknown> }\n\nexport type RepositoryPolicy = {\n changesets?: PolicySelection\n dependabot?: PolicySelection\n pnpm?: false | { minimumReleaseAge?: number }\n adoption?: false | AdoptionPolicy\n}\n\nexport type AdoptionPolicy = {\n minimumRasStackVersion?: string\n minimumWorkflowRasStackVersion?: string\n node?: string\n pnpm?: string\n just?: string\n requiredReferences?: string[]\n}\n\nexport type AdoptionSnapshot = {\n manifest: Record<string, unknown>\n files: Map<string, string>\n}\n\nexport async function syncRepositoryPolicy(root: string, mode: 'check' | 'write') {\n const config = repositoryPolicy(await readFile(join(root, 'ras-stack.policy.json'), 'utf8'))\n const files = await renderedPolicyFiles(root, config)\n const compared = await Promise.all(\n [...files].map(async ([path, expected]) => {\n const absolute = join(root, path)\n const actual = await readFile(absolute, 'utf8').catch(() => undefined)\n if (actual === expected) return undefined\n if (mode === 'write') {\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, expected)\n }\n return path\n }),\n )\n return compared.filter((path) => path !== undefined)\n}\n\nexport async function checkRepositoryPolicy(root: string) {\n const files = await syncRepositoryPolicy(root, 'check')\n const config = repositoryPolicy(await readFile(join(root, 'ras-stack.policy.json'), 'utf8'))\n return [...files.map((path) => `policy drift: ${path}`), ...(config.adoption ? await adoptionDrift(root, config.adoption) : [])]\n}\n\nexport async function syncAdoptionPolicy(root: string, mode: 'check' | 'write') {\n const config = repositoryPolicy(await readFile(join(root, 'ras-stack.policy.json'), 'utf8'))\n if (!config.adoption) return []\n const files = await renderedAdoptionFiles(root, config.adoption)\n const changed = await Promise.all(\n [...files].map(async ([path, expected]) => {\n const absolute = join(root, path)\n const actual = await readFile(absolute, 'utf8')\n if (actual === expected) return undefined\n if (mode === 'write') await writeFile(absolute, expected)\n return path\n }),\n )\n return changed.filter((path) => path !== undefined)\n}\n\nexport async function adoptionDrift(root: string, policy: AdoptionPolicy) {\n const manifest = JSON.parse(await readFile(join(root, 'package.json'), 'utf8')) as Record<string, unknown>\n const files = await adoptionFiles(root)\n return adoptionSnapshotDrift({ manifest, files }, policy)\n}\n\nexport function adoptionSnapshotDrift(snapshot: AdoptionSnapshot, policy: AdoptionPolicy) {\n const drift: string[] = []\n const { manifest, files } = snapshot\n if (policy.node && manifest.engines && plainObject(manifest.engines) && manifest.engines.node !== policy.node) {\n drift.push(`toolchain drift: package.json engines.node must be ${policy.node}`)\n }\n if (policy.pnpm && manifest.packageManager !== `pnpm@${policy.pnpm}`) {\n drift.push(`toolchain drift: package.json packageManager must be pnpm@${policy.pnpm}`)\n }\n if (policy.minimumRasStackVersion) {\n const dependency = dependencyVersion(manifest, 'ras-stack')\n if (dependency && compareVersions(dependency, policy.minimumRasStackVersion) < 0) {\n drift.push(`ras-stack drift: package.json uses ${dependency}, minimum is ${policy.minimumRasStackVersion}`)\n }\n }\n\n const workflows = new Map([...files].filter(([path]) => path.startsWith('.github/') && /\\.ya?ml$/.test(path)))\n const workflowMinimum = policy.minimumWorkflowRasStackVersion ?? policy.minimumRasStackVersion\n for (const [path, source] of workflows) {\n if (workflowMinimum) {\n for (const match of source.matchAll(/richardsolomou\\/ras-stack\\/[^\\s'\"}]+@v(\\d+\\.\\d+\\.\\d+)/g)) {\n const version = match[1]\n if (version && compareVersions(version, workflowMinimum) < 0) {\n drift.push(`ras-stack drift: ${path} uses v${version}, minimum is v${workflowMinimum}`)\n }\n }\n }\n }\n if (\n policy.just &&\n ![...workflows.values()].some(\n (source) => source.includes(`just-version: '${policy.just}'`) || source.includes(`just-version: ${policy.just}`),\n )\n ) {\n drift.push(`toolchain drift: no workflow declares just-version ${policy.just}`)\n }\n for (const reference of policy.requiredReferences ?? []) {\n if (![...files.values()].some((source) => source.includes(reference))) {\n drift.push(`shared config drift: no configuration references ${reference}`)\n }\n }\n return [...new Set(drift)]\n}\n\nexport async function renderedPolicyFiles(root: string, config: RepositoryPolicy) {\n const files = new Map<string, string>()\n if (config.changesets) {\n files.set('.changeset/config.json', `${JSON.stringify(selectedPolicy(changesetsPolicy, config.changesets), null, 2)}\\n`)\n }\n if (config.dependabot) {\n files.set('.github/dependabot.yml', stringify(selectedPolicy(dependabotPolicy, config.dependabot), { lineWidth: 0, singleQuote: true }))\n }\n if (config.pnpm) {\n const path = join(root, 'pnpm-workspace.yaml')\n const document = parseDocument(await readFile(path, 'utf8').catch(() => ''))\n document.set('minimumReleaseAge', config.pnpm.minimumReleaseAge ?? 10_080)\n files.set('pnpm-workspace.yaml', document.toString({ lineWidth: 0 }))\n }\n return files\n}\n\nfunction repositoryPolicy(source: string): RepositoryPolicy {\n const value = JSON.parse(source) as unknown\n if (!plainObject(value)) throw new Error('ras-stack.policy.json must contain an object')\n for (const name of ['changesets', 'dependabot'] as const) validateSelection(name, value[name])\n const pnpm = value.pnpm\n if (pnpm !== undefined && pnpm !== false) {\n if (!plainObject(pnpm)) throw new Error('pnpm policy must be false or an object')\n const age = pnpm.minimumReleaseAge\n if (age !== undefined && (typeof age !== 'number' || !Number.isInteger(age) || age < 0)) {\n throw new Error('pnpm.minimumReleaseAge must be a non-negative integer')\n }\n }\n const adoption = value.adoption\n if (adoption !== undefined && adoption !== false) {\n if (!plainObject(adoption)) throw new Error('adoption policy must be false or an object')\n for (const key of ['minimumRasStackVersion', 'minimumWorkflowRasStackVersion', 'node', 'pnpm', 'just']) {\n if (adoption[key] !== undefined && typeof adoption[key] !== 'string') throw new Error(`adoption.${key} must be a string`)\n }\n if (adoption.requiredReferences !== undefined && !stringArray(adoption.requiredReferences)) {\n throw new Error('adoption.requiredReferences must be an array of strings')\n }\n }\n return value\n}\n\nfunction dependencyVersion(manifest: Record<string, unknown>, name: string) {\n for (const field of ['dependencies', 'devDependencies']) {\n const dependencies = manifest[field]\n const value = plainObject(dependencies) ? dependencies[name] : undefined\n if (typeof value === 'string') return /\\d+\\.\\d+\\.\\d+/.exec(value)?.[0]\n }\n return undefined\n}\n\nfunction compareVersions(left: string, right: string) {\n const a = left.split('.').map(Number)\n const b = right.split('.').map(Number)\n for (let index = 0; index < 3; index += 1) {\n if (a[index] !== b[index]) return (a[index] ?? 0) - (b[index] ?? 0)\n }\n return 0\n}\n\nasync function textFiles(directory: string, root = directory): Promise<Map<string, string>> {\n const files = new Map<string, string>()\n const entries = await readdir(directory, { withFileTypes: true }).catch(() => [])\n const results = await Promise.all(\n entries.map(async (entry) => {\n const path = join(directory, entry.name)\n if (entry.isDirectory()) return textFiles(path, root)\n if (/\\.ya?ml$/.test(entry.name)) return new Map([[path.slice(root.length + 1), await readFile(path, 'utf8')]])\n return new Map<string, string>()\n }),\n )\n for (const result of results) {\n for (const [path, source] of result) files.set(path, source)\n }\n return files\n}\n\nasync function adoptionFiles(root: string) {\n const files = await textFiles(join(root, '.github'), root)\n const entries = await readdir(root, { withFileTypes: true })\n await Promise.all(\n entries.map(async (entry) => {\n if (!entry.isFile() || !/^(?:ras-stack\\.policy|oxlint|tsconfig(?:\\.[^.]+)*)\\.json$/.test(entry.name)) return\n files.set(entry.name, await readFile(join(root, entry.name), 'utf8'))\n }),\n )\n return files\n}\n\nasync function renderedAdoptionFiles(root: string, policy: AdoptionPolicy) {\n const files = new Map<string, string>()\n const manifestPath = join(root, 'package.json')\n const manifestSource = await readFile(manifestPath, 'utf8')\n const manifest = JSON.parse(manifestSource) as Record<string, unknown>\n if (policy.node) {\n const engines = plainObject(manifest.engines) ? manifest.engines : {}\n manifest.engines = { ...engines, node: policy.node }\n }\n if (policy.pnpm) manifest.packageManager = `pnpm@${policy.pnpm}`\n if (policy.minimumRasStackVersion) {\n for (const field of ['dependencies', 'devDependencies']) {\n const dependencies = manifest[field]\n if (!plainObject(dependencies) || typeof dependencies['ras-stack'] !== 'string') continue\n dependencies['ras-stack'] = versionAtLeast(dependencies['ras-stack'], policy.minimumRasStackVersion)\n }\n }\n const renderedManifest = `${JSON.stringify(manifest, null, 2)}\\n`\n if (renderedManifest !== manifestSource) files.set('package.json', renderedManifest)\n\n const workflowVersion = policy.minimumWorkflowRasStackVersion ?? policy.minimumRasStackVersion\n const workflows = await textFiles(join(root, '.github'), root)\n for (const [path, source] of workflows) {\n let rendered = source\n if (workflowVersion) {\n rendered = rendered.replace(/(richardsolomou\\/ras-stack\\/[^\\s'\"}]+@v)(\\d+\\.\\d+\\.\\d+)/g, (reference, prefix, current) =>\n compareVersions(current, workflowVersion) < 0 ? `${prefix}${workflowVersion}` : reference,\n )\n }\n if (policy.just) {\n rendered = rendered.replace(/(just-version:\\s*)(['\"]?)\\d+\\.\\d+\\.\\d+\\2/g, `$1$2${policy.just}$2`)\n rendered = rendered.replace(\n /(richardsolomou\\/ras-stack\\/actions\\/setup-just@[^\\n]+\\n(?:(?!\\n\\s*-\\s+uses:)[\\s\\S]){0,300}?\\n\\s+version:\\s*)(['\"]?)\\d+\\.\\d+\\.\\d+\\2/g,\n `$1$2${policy.just}$2`,\n )\n }\n if (rendered !== source) files.set(path, rendered)\n }\n return files\n}\n\nfunction versionAtLeast(current: string, version: string) {\n const match = /^(\\s*(?:\\^|~|>=|>|<=|<|=)?\\s*)\\d+\\.\\d+\\.\\d+(.*)$/.exec(current)\n const currentVersion = /\\d+\\.\\d+\\.\\d+/.exec(current)?.[0]\n if (currentVersion && compareVersions(currentVersion, version) >= 0) return current\n return match ? `${match[1]}${version}${match[2]}` : version\n}\n\nfunction validateSelection(name: string, value: unknown) {\n if (value === undefined || typeof value === 'boolean') return\n if (!plainObject(value) || (value.overrides !== undefined && !plainObject(value.overrides))) {\n throw new Error(`${name} policy must be a boolean or an object with overrides`)\n }\n}\n\nfunction selectedPolicy(base: Record<string, unknown>, selection: Exclude<PolicySelection, false>) {\n return selection === true ? base : deepMerge(base, selection.overrides ?? {})\n}\n\nfunction deepMerge(base: Record<string, unknown>, overrides: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n [...new Set([...Object.keys(base), ...Object.keys(overrides)])].map((key) => {\n const left = base[key]\n const right = overrides[key]\n return [key, plainObject(left) && plainObject(right) ? deepMerge(left, right) : right === undefined ? left : right]\n }),\n )\n}\n\nfunction plainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction stringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === 'string')\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { parseDocument, stringify } from 'yaml'\n\nconst changesetsPolicy = {\n $schema: 'https://unpkg.com/@changesets/config@3.1.2/schema.json',\n changelog: '@changesets/cli/changelog',\n commit: false,\n fixed: [],\n linked: [],\n access: 'public',\n baseBranch: 'main',\n updateInternalDependencies: 'patch',\n ignore: [],\n}\n\nconst dependabotPolicy = {\n version: 2,\n updates: [\n {\n 'package-ecosystem': 'npm',\n directory: '/',\n schedule: { interval: 'weekly' },\n cooldown: { 'default-days': 7 },\n groups: { 'javascript-dependencies': { patterns: ['*'] } },\n },\n {\n 'package-ecosystem': 'github-actions',\n directory: '/',\n schedule: { interval: 'weekly' },\n cooldown: { 'default-days': 7 },\n },\n ],\n}\n\ntype PolicySelection = boolean | { overrides?: Record<string, unknown> }\n\nexport type RepositoryPolicy = {\n changesets?: PolicySelection\n dependabot?: PolicySelection\n pnpm?: false | { minimumReleaseAge?: number }\n}\n\nexport async function syncRepositoryPolicy(root: string, mode: 'check' | 'write') {\n const config = repositoryPolicy(await readFile(join(root, 'ras-stack.policy.json'), 'utf8'))\n const files = await renderedPolicyFiles(root, config)\n const compared = await Promise.all(\n [...files].map(async ([path, expected]) => {\n const absolute = join(root, path)\n const actual = await readFile(absolute, 'utf8').catch(() => undefined)\n if (actual === expected) return undefined\n if (mode === 'write') {\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, expected)\n }\n return path\n }),\n )\n return compared.filter((path) => path !== undefined)\n}\n\nexport async function checkRepositoryPolicy(root: string) {\n const files = await syncRepositoryPolicy(root, 'check')\n return files.map((path) => `policy drift: ${path}`)\n}\n\nexport async function renderedPolicyFiles(root: string, config: RepositoryPolicy) {\n const files = new Map<string, string>()\n if (config.changesets) {\n files.set('.changeset/config.json', `${JSON.stringify(selectedPolicy(changesetsPolicy, config.changesets), null, 2)}\\n`)\n }\n if (config.dependabot) {\n files.set('.github/dependabot.yml', stringify(selectedPolicy(dependabotPolicy, config.dependabot), { lineWidth: 0, singleQuote: true }))\n }\n if (config.pnpm) {\n const path = join(root, 'pnpm-workspace.yaml')\n const document = parseDocument(await readFile(path, 'utf8').catch(() => ''))\n document.set('minimumReleaseAge', config.pnpm.minimumReleaseAge ?? 10_080)\n files.set('pnpm-workspace.yaml', document.toString({ lineWidth: 0 }))\n }\n return files\n}\n\nfunction repositoryPolicy(source: string): RepositoryPolicy {\n const value = JSON.parse(source) as unknown\n if (!plainObject(value)) throw new Error('ras-stack.policy.json must contain an object')\n for (const name of ['changesets', 'dependabot'] as const) validateSelection(name, value[name])\n const pnpm = value.pnpm\n if (pnpm !== undefined && pnpm !== false) {\n if (!plainObject(pnpm)) throw new Error('pnpm policy must be false or an object')\n const age = pnpm.minimumReleaseAge\n if (age !== undefined && (typeof age !== 'number' || !Number.isInteger(age) || age < 0)) {\n throw new Error('pnpm.minimumReleaseAge must be a non-negative integer')\n }\n }\n return value\n}\n\nfunction validateSelection(name: string, value: unknown) {\n if (value === undefined || typeof value === 'boolean') return\n if (!plainObject(value) || (value.overrides !== undefined && !plainObject(value.overrides))) {\n throw new Error(`${name} policy must be a boolean or an object with overrides`)\n }\n}\n\nfunction selectedPolicy(base: Record<string, unknown>, selection: Exclude<PolicySelection, false>) {\n return selection === true ? base : deepMerge(base, selection.overrides ?? {})\n}\n\nfunction deepMerge(base: Record<string, unknown>, overrides: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n [...new Set([...Object.keys(base), ...Object.keys(overrides)])].map((key) => {\n const left = base[key]\n const right = overrides[key]\n return [key, plainObject(left) && plainObject(right) ? deepMerge(left, right) : right === undefined ? left : right]\n }),\n )\n}\n\nfunction plainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n"]}
|
package/dist/policy/init.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type AdoptionPolicy } from './index.js';
|
|
2
1
|
export type InitStepName = 'policy' | 'toolchain' | 'typescript' | 'oxlint' | 'workflow' | 'justfile';
|
|
3
2
|
export type InitStep = {
|
|
4
3
|
name: InitStepName;
|
|
@@ -15,7 +14,11 @@ export type PlannedFile = {
|
|
|
15
14
|
contents: string;
|
|
16
15
|
existing?: string;
|
|
17
16
|
};
|
|
18
|
-
export declare const
|
|
17
|
+
export declare const INIT_TOOLCHAIN: {
|
|
18
|
+
node: string;
|
|
19
|
+
pnpm: string;
|
|
20
|
+
just: string;
|
|
21
|
+
};
|
|
19
22
|
export declare const INIT_STEPS: readonly InitStep[];
|
|
20
23
|
export declare function planRepositoryInit(root: string, answers: InitAnswers, release?: string): Promise<PlannedFile[]>;
|
|
21
24
|
export declare function applyRepositoryInit(root: string, files: readonly PlannedFile[]): Promise<string[]>;
|
package/dist/policy/init.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { renderedPolicyFiles } from './index.js';
|
|
4
|
-
//
|
|
5
|
-
export const
|
|
4
|
+
// Toolchain a generated repository starts on. `init.test.ts` holds these to what this repository itself runs.
|
|
5
|
+
export const INIT_TOOLCHAIN = {
|
|
6
6
|
node: '>=24 <25',
|
|
7
7
|
pnpm: '11.15.0',
|
|
8
8
|
just: '1.58.0',
|
|
@@ -24,12 +24,7 @@ export async function planRepositoryInit(root, answers, release) {
|
|
|
24
24
|
const selected = new Set(answers.steps);
|
|
25
25
|
const planned = [];
|
|
26
26
|
if (selected.has('policy')) {
|
|
27
|
-
const policy = {
|
|
28
|
-
changesets: true,
|
|
29
|
-
dependabot: true,
|
|
30
|
-
pnpm: {},
|
|
31
|
-
adoption: { ...INIT_ADOPTION, minimumRasStackVersion: version, minimumWorkflowRasStackVersion: version },
|
|
32
|
-
};
|
|
27
|
+
const policy = { changesets: true, dependabot: true, pnpm: {} };
|
|
33
28
|
planned.push({ path: 'ras-stack.policy.json', contents: `${JSON.stringify(policy, null, 2)}\n` });
|
|
34
29
|
for (const [path, contents] of await renderedPolicyFiles(root, policy))
|
|
35
30
|
planned.push({ path, contents });
|
|
@@ -39,7 +34,7 @@ export async function planRepositoryInit(root, answers, release) {
|
|
|
39
34
|
if (!manifest)
|
|
40
35
|
throw new Error('package.json is required before the toolchain can be configured');
|
|
41
36
|
const engines = manifest.engines && typeof manifest.engines === 'object' ? manifest.engines : {};
|
|
42
|
-
const configured = { ...manifest, engines: { ...engines, node:
|
|
37
|
+
const configured = { ...manifest, engines: { ...engines, node: INIT_TOOLCHAIN.node }, packageManager: `pnpm@${INIT_TOOLCHAIN.pnpm}` };
|
|
43
38
|
planned.push({ path: 'package.json', contents: `${JSON.stringify(configured, null, 2)}\n` });
|
|
44
39
|
}
|
|
45
40
|
if (selected.has('typescript')) {
|
|
@@ -90,7 +85,7 @@ jobs:
|
|
|
90
85
|
uses: richardsolomou/ras-stack/.github/workflows/check-js.yml@v${version}
|
|
91
86
|
with:
|
|
92
87
|
command: just check
|
|
93
|
-
just-version: '${
|
|
88
|
+
just-version: '${INIT_TOOLCHAIN.just}'
|
|
94
89
|
`;
|
|
95
90
|
}
|
|
96
91
|
const JUSTFILE = `default:
|
package/dist/policy/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/policy/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,mBAAmB,EAAuB,MAAM,YAAY,CAAA;AAYrE,kHAAkH;AAClH,MAAM,CAAC,MAAM,aAAa,GAAmB;IAC3C,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,QAAQ;CACf,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAwB;IAC7C;QACE,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,mBAAmB;QAC1B,MAAM,EAAE,oFAAoF;KAC7F;IACD,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,EAAE,iDAAiD,EAAE;IAC7G,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,0BAA0B,EAAE,MAAM,EAAE,yCAAyC,EAAE;IAC5G,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,EAAE,2CAA2C,EAAE;IACpG,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,4DAA4D,EAAE;IAChH,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,uCAAuC,EAAE;CAC/F,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAY,EAAE,OAAoB,EAAE,OAAgB;IAC3F,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,MAAM,eAAe,EAAE,CAAC,CAAA;IACpD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IACvC,MAAM,OAAO,GAAkB,EAAE,CAAA;IAEjC,IAAI,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG;YACb,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE,EAAE;YACR,QAAQ,EAAE,EAAE,GAAG,aAAa,EAAE,sBAAsB,EAAE,OAAO,EAAE,8BAA8B,EAAE,OAAO,EAAE;SACzG,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QACjG,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC1G,CAAC;IAED,IAAI,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAA;QAC3D,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAA;QACjG,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;QAChG,MAAM,UAAU,GAAG,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,EAAE,cAAc,EAAE,QAAQ,aAAa,CAAC,IAAI,EAAE,EAAE,CAAA;QACnI,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;IAC9F,CAAC;IAED,IAAI,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,gBAAgB,IAAI,SAAS,CAAA;QACpD,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,eAAe;YACrB,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,8CAA8C,MAAM,OAAO,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI;SACnL,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,gBAAgB;YACtB,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,6CAA6C,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI;SACvG,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC7G,IAAI,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAA;IAEpF,MAAM,OAAO,CAAC,GAAG,CACf,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;QACrF,IAAI,QAAQ,KAAK,SAAS;YAAE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;IACtD,CAAC,CAAC,CACH,CAAA;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAY,EAAE,KAA6B;IACnF,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QACtC,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACnD,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC1C,CAAC,CAAC,CACH,CAAA;IACD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACvC,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAC/B,OAAO;;;;;;;;;;;;qEAY4D,OAAO;;;uBAGrD,aAAa,CAAC,IAAI;CACxC,CAAA;AACD,CAAC;AAED,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBhB,CAAA;AAED,KAAK,UAAU,QAAQ,CAAC,IAAkB;IACxC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IAClE,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAA6B,CAAA;AAC3F,CAAC;AAED,qHAAqH;AACrH,KAAK,UAAU,eAAe;IAC5B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IAC/E,MAAM,OAAO,GAAG,QAAQ,EAAE,OAAO,CAAA;IACjC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACpF,OAAO,OAAO,CAAA;AAChB,CAAC","sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { renderedPolicyFiles, type AdoptionPolicy } from './index.js'\n\nexport type InitStepName = 'policy' | 'toolchain' | 'typescript' | 'oxlint' | 'workflow' | 'justfile'\n\nexport type InitStep = { name: InitStepName; title: string; detail: string }\n\nexport type TypeScriptPreset = 'library' | 'bundler' | 'node-bundler' | 'browser' | 'tanstack'\n\nexport type InitAnswers = { steps: readonly InitStepName[]; typescriptPreset?: TypeScriptPreset }\n\nexport type PlannedFile = { path: string; contents: string; existing?: string }\n\n// Adoption values a generated repository starts from. `init.test.ts` holds these to this repository's own policy.\nexport const INIT_ADOPTION: AdoptionPolicy = {\n node: '>=24 <25',\n pnpm: '11.15.0',\n just: '1.58.0',\n}\n\nexport const INIT_STEPS: readonly InitStep[] = [\n {\n name: 'policy',\n title: 'Repository policy',\n detail: 'ras-stack.policy.json plus the Changesets, Dependabot, and pnpm files it generates',\n },\n { name: 'toolchain', title: 'Toolchain versions', detail: 'engines.node and packageManager in package.json' },\n { name: 'typescript', title: 'TypeScript configuration', detail: 'tsconfig.json extending a shared preset' },\n { name: 'oxlint', title: 'Lint configuration', detail: '.oxlintrc.json extending the shared rules' },\n { name: 'workflow', title: 'CI workflow', detail: '.github/workflows/ci.yml calling the shared check workflow' },\n { name: 'justfile', title: 'Command runner', detail: 'justfile wrapping the package scripts' },\n]\n\nexport async function planRepositoryInit(root: string, answers: InitAnswers, release?: string): Promise<PlannedFile[]> {\n const version = release ?? (await rasStackVersion())\n const selected = new Set(answers.steps)\n const planned: PlannedFile[] = []\n\n if (selected.has('policy')) {\n const policy = {\n changesets: true,\n dependabot: true,\n pnpm: {},\n adoption: { ...INIT_ADOPTION, minimumRasStackVersion: version, minimumWorkflowRasStackVersion: version },\n }\n planned.push({ path: 'ras-stack.policy.json', contents: `${JSON.stringify(policy, null, 2)}\\n` })\n for (const [path, contents] of await renderedPolicyFiles(root, policy)) planned.push({ path, contents })\n }\n\n if (selected.has('toolchain')) {\n const manifest = await readJson(join(root, 'package.json'))\n if (!manifest) throw new Error('package.json is required before the toolchain can be configured')\n const engines = manifest.engines && typeof manifest.engines === 'object' ? manifest.engines : {}\n const configured = { ...manifest, engines: { ...engines, node: INIT_ADOPTION.node }, packageManager: `pnpm@${INIT_ADOPTION.pnpm}` }\n planned.push({ path: 'package.json', contents: `${JSON.stringify(configured, null, 2)}\\n` })\n }\n\n if (selected.has('typescript')) {\n const preset = answers.typescriptPreset ?? 'library'\n planned.push({\n path: 'tsconfig.json',\n contents: `${JSON.stringify({ extends: `./node_modules/ras-stack/config/typescript/${preset}.json`, compilerOptions: { types: ['node'] }, include: ['src/**/*.ts'] }, null, 2)}\\n`,\n })\n }\n\n if (selected.has('oxlint')) {\n planned.push({\n path: '.oxlintrc.json',\n contents: `${JSON.stringify({ extends: ['./node_modules/ras-stack/config/oxlint.json'] }, null, 2)}\\n`,\n })\n }\n\n if (selected.has('workflow')) planned.push({ path: '.github/workflows/ci.yml', contents: workflow(version) })\n if (selected.has('justfile')) planned.push({ path: 'justfile', contents: JUSTFILE })\n\n await Promise.all(\n planned.map(async (file) => {\n const existing = await readFile(join(root, file.path), 'utf8').catch(() => undefined)\n if (existing !== undefined) file.existing = existing\n }),\n )\n return planned\n}\n\nexport async function applyRepositoryInit(root: string, files: readonly PlannedFile[]) {\n await Promise.all(\n files.map(async (file) => {\n const absolute = join(root, file.path)\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, file.contents)\n }),\n )\n return files.map((file) => file.path)\n}\n\nfunction workflow(version: string) {\n return `name: CI\n\non:\n pull_request:\n push:\n branches: [main]\n\npermissions:\n contents: read\n\njobs:\n check:\n uses: richardsolomou/ras-stack/.github/workflows/check-js.yml@v${version}\n with:\n command: just check\n just-version: '${INIT_ADOPTION.just}'\n`\n}\n\nconst JUSTFILE = `default:\n @just --list\n\ninstall:\n corepack enable\n pnpm install\n\nformat:\n pnpm format\n\nlint:\n pnpm lint\n\ntypecheck:\n pnpm typecheck\n\ntest *args:\n pnpm exec vitest run {{ args }}\n\ncheck:\n pnpm check\n`\n\nasync function readJson(path: string | URL) {\n const source = await readFile(path, 'utf8').catch(() => undefined)\n return source === undefined ? undefined : (JSON.parse(source) as Record<string, unknown>)\n}\n\n// The generated workflow pins the release doing the generating, so a new repository starts on a version that exists.\nasync function rasStackVersion() {\n const manifest = await readJson(new URL('../../package.json', import.meta.url))\n const version = manifest?.version\n if (typeof version !== 'string') throw new Error('ras-stack version is unavailable')\n return version\n}\n"]}
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/policy/init.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { renderedPolicyFiles } from './index.js'\n\nexport type InitStepName = 'policy' | 'toolchain' | 'typescript' | 'oxlint' | 'workflow' | 'justfile'\n\nexport type InitStep = { name: InitStepName; title: string; detail: string }\n\nexport type TypeScriptPreset = 'library' | 'bundler' | 'node-bundler' | 'browser' | 'tanstack'\n\nexport type InitAnswers = { steps: readonly InitStepName[]; typescriptPreset?: TypeScriptPreset }\n\nexport type PlannedFile = { path: string; contents: string; existing?: string }\n\n// Toolchain a generated repository starts on. `init.test.ts` holds these to what this repository itself runs.\nexport const INIT_TOOLCHAIN = {\n node: '>=24 <25',\n pnpm: '11.15.0',\n just: '1.58.0',\n}\n\nexport const INIT_STEPS: readonly InitStep[] = [\n {\n name: 'policy',\n title: 'Repository policy',\n detail: 'ras-stack.policy.json plus the Changesets, Dependabot, and pnpm files it generates',\n },\n { name: 'toolchain', title: 'Toolchain versions', detail: 'engines.node and packageManager in package.json' },\n { name: 'typescript', title: 'TypeScript configuration', detail: 'tsconfig.json extending a shared preset' },\n { name: 'oxlint', title: 'Lint configuration', detail: '.oxlintrc.json extending the shared rules' },\n { name: 'workflow', title: 'CI workflow', detail: '.github/workflows/ci.yml calling the shared check workflow' },\n { name: 'justfile', title: 'Command runner', detail: 'justfile wrapping the package scripts' },\n]\n\nexport async function planRepositoryInit(root: string, answers: InitAnswers, release?: string): Promise<PlannedFile[]> {\n const version = release ?? (await rasStackVersion())\n const selected = new Set(answers.steps)\n const planned: PlannedFile[] = []\n\n if (selected.has('policy')) {\n const policy = { changesets: true, dependabot: true, pnpm: {} }\n planned.push({ path: 'ras-stack.policy.json', contents: `${JSON.stringify(policy, null, 2)}\\n` })\n for (const [path, contents] of await renderedPolicyFiles(root, policy)) planned.push({ path, contents })\n }\n\n if (selected.has('toolchain')) {\n const manifest = await readJson(join(root, 'package.json'))\n if (!manifest) throw new Error('package.json is required before the toolchain can be configured')\n const engines = manifest.engines && typeof manifest.engines === 'object' ? manifest.engines : {}\n const configured = { ...manifest, engines: { ...engines, node: INIT_TOOLCHAIN.node }, packageManager: `pnpm@${INIT_TOOLCHAIN.pnpm}` }\n planned.push({ path: 'package.json', contents: `${JSON.stringify(configured, null, 2)}\\n` })\n }\n\n if (selected.has('typescript')) {\n const preset = answers.typescriptPreset ?? 'library'\n planned.push({\n path: 'tsconfig.json',\n contents: `${JSON.stringify({ extends: `./node_modules/ras-stack/config/typescript/${preset}.json`, compilerOptions: { types: ['node'] }, include: ['src/**/*.ts'] }, null, 2)}\\n`,\n })\n }\n\n if (selected.has('oxlint')) {\n planned.push({\n path: '.oxlintrc.json',\n contents: `${JSON.stringify({ extends: ['./node_modules/ras-stack/config/oxlint.json'] }, null, 2)}\\n`,\n })\n }\n\n if (selected.has('workflow')) planned.push({ path: '.github/workflows/ci.yml', contents: workflow(version) })\n if (selected.has('justfile')) planned.push({ path: 'justfile', contents: JUSTFILE })\n\n await Promise.all(\n planned.map(async (file) => {\n const existing = await readFile(join(root, file.path), 'utf8').catch(() => undefined)\n if (existing !== undefined) file.existing = existing\n }),\n )\n return planned\n}\n\nexport async function applyRepositoryInit(root: string, files: readonly PlannedFile[]) {\n await Promise.all(\n files.map(async (file) => {\n const absolute = join(root, file.path)\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, file.contents)\n }),\n )\n return files.map((file) => file.path)\n}\n\nfunction workflow(version: string) {\n return `name: CI\n\non:\n pull_request:\n push:\n branches: [main]\n\npermissions:\n contents: read\n\njobs:\n check:\n uses: richardsolomou/ras-stack/.github/workflows/check-js.yml@v${version}\n with:\n command: just check\n just-version: '${INIT_TOOLCHAIN.just}'\n`\n}\n\nconst JUSTFILE = `default:\n @just --list\n\ninstall:\n corepack enable\n pnpm install\n\nformat:\n pnpm format\n\nlint:\n pnpm lint\n\ntypecheck:\n pnpm typecheck\n\ntest *args:\n pnpm exec vitest run {{ args }}\n\ncheck:\n pnpm check\n`\n\nasync function readJson(path: string | URL) {\n const source = await readFile(path, 'utf8').catch(() => undefined)\n return source === undefined ? undefined : (JSON.parse(source) as Record<string, unknown>)\n}\n\n// The generated workflow pins the release doing the generating, so a new repository starts on a version that exists.\nasync function rasStackVersion() {\n const manifest = await readJson(new URL('../../package.json', import.meta.url))\n const version = manifest?.version\n if (typeof version !== 'string') throw new Error('ras-stack version is unavailable')\n return version\n}\n"]}
|