@smoothbricks/cli 0.10.4 → 0.10.6
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/dist/cli.js +5 -5
- package/dist/github-ci/index.d.ts.map +1 -1
- package/dist/github-ci/index.js +5 -3
- package/dist/lib/json.d.ts +5 -1
- package/dist/lib/json.d.ts.map +1 -1
- package/dist/lib/json.js +18 -16
- package/dist/monorepo/ci-workflow.d.ts +2 -0
- package/dist/monorepo/ci-workflow.d.ts.map +1 -1
- package/dist/monorepo/ci-workflow.js +10 -4
- package/dist/monorepo/github-runs-on.d.ts +14 -0
- package/dist/monorepo/github-runs-on.d.ts.map +1 -0
- package/dist/monorepo/github-runs-on.js +43 -0
- package/dist/monorepo/index.d.ts +3 -3
- package/dist/monorepo/index.d.ts.map +1 -1
- package/dist/monorepo/index.js +20 -8
- package/dist/monorepo/lockfile.d.ts +2 -1
- package/dist/monorepo/lockfile.d.ts.map +1 -1
- package/dist/monorepo/lockfile.js +1 -1
- package/dist/monorepo/managed-files.d.ts +30 -3
- package/dist/monorepo/managed-files.d.ts.map +1 -1
- package/dist/monorepo/managed-files.js +83 -63
- package/dist/monorepo/packs/index.js +2 -2
- package/dist/monorepo/publish-workflow.d.ts +3 -0
- package/dist/monorepo/publish-workflow.d.ts.map +1 -1
- package/dist/monorepo/publish-workflow.js +17 -14
- package/dist/monorepo/tool-validation.d.ts +2 -2
- package/dist/monorepo/tool-validation.d.ts.map +1 -1
- package/dist/monorepo/tool-validation.js +110 -16
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +6 -0
- package/managed/raw/envrc +5 -3
- package/managed/raw/patches/ttsc@0.19.3.patch +67 -0
- package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +24 -7
- package/managed/raw/tooling/direnv/setup-environment.ts +23 -3
- package/managed/templates/github/actions/cache-nix-devenv/action.yml +13 -11
- package/managed/templates/github/actions/save-nix-devenv/action.yml +34 -3
- package/managed/templates/github/actions/setup-devenv/action.yml +44 -15
- package/managed/templates/github/workflows/managed-files.yml +64 -12
- package/package.json +2 -2
- package/src/cli.ts +6 -6
- package/src/github-ci/index.test.ts +3 -3
- package/src/github-ci/index.ts +6 -3
- package/src/lib/json.ts +5 -1
- package/src/monorepo/__tests__/ci-workflow.test.ts +37 -1
- package/src/monorepo/__tests__/publish-workflow.test.ts +28 -1
- package/src/monorepo/ci-workflow.ts +14 -4
- package/src/monorepo/github-runs-on.ts +45 -0
- package/src/monorepo/index.ts +20 -8
- package/src/monorepo/lockfile.ts +3 -2
- package/src/monorepo/managed-files.test.ts +49 -0
- package/src/monorepo/managed-files.ts +105 -64
- package/src/monorepo/packs/index.ts +2 -2
- package/src/monorepo/publish-workflow.ts +23 -15
- package/src/monorepo/tool-validation.test.ts +38 -16
- package/src/monorepo/tool-validation.ts +114 -16
- package/src/release/index.ts +6 -0
|
@@ -5,13 +5,19 @@ import { cliPackageVersion, isSmoothBricksCodebasePackageName } from '../lib/cli
|
|
|
5
5
|
import { ensureDependencyMap, readJsonObject, setPackageStringField, setStringProperty, writeJsonObject, } from '../lib/json.js';
|
|
6
6
|
import { readPackageJsonObject } from '../lib/workspace.js';
|
|
7
7
|
const isRegistryPackument = (() => {
|
|
8
|
-
const _io0 = input => "object" === typeof input.versions && null !== input.versions && false === Array.isArray(input.versions) && _io1(input.versions);
|
|
8
|
+
const _io0 = input => "object" === typeof input.versions && null !== input.versions && false === Array.isArray(input.versions) && _io1(input.versions) && (undefined === input["dist-tags"] || "object" === typeof input["dist-tags"] && null !== input["dist-tags"] && false === Array.isArray(input["dist-tags"]) && _io2(input["dist-tags"]));
|
|
9
9
|
const _io1 = input => Object.keys(input).every(key => {
|
|
10
10
|
const value = input[key];
|
|
11
11
|
if (undefined === value)
|
|
12
12
|
return true;
|
|
13
13
|
return true;
|
|
14
14
|
});
|
|
15
|
+
const _io2 = input => Object.keys(input).every(key => {
|
|
16
|
+
const value = input[key];
|
|
17
|
+
if (undefined === value)
|
|
18
|
+
return true;
|
|
19
|
+
return "string" === typeof value;
|
|
20
|
+
});
|
|
15
21
|
return input => "object" === typeof input && null !== input && _io0(input);
|
|
16
22
|
})();
|
|
17
23
|
const rootDevDependencies = [
|
|
@@ -34,10 +40,14 @@ const rootDevDependencies = [
|
|
|
34
40
|
},
|
|
35
41
|
{ name: 'nx', fallbackVersion: '23.1.0', minimumVersion: '23.1.0' },
|
|
36
42
|
{ name: 'prettier', fallbackVersion: '^3.6.1', minimumVersion: '3.6.0', prefix: '^' },
|
|
37
|
-
|
|
43
|
+
// Exact pin: Bun patchedDependencies keys are version-locked (see patches/ttsc@0.19.3.patch).
|
|
44
|
+
{ name: 'ttsc', fallbackVersion: '0.19.3' },
|
|
38
45
|
// Nx and typescript-eslint still load the TypeScript JS API (6.x).
|
|
39
46
|
// Compilation is exclusively delegated to ttsc by the Nx plugin targets.
|
|
40
|
-
{ name: 'typescript', fallbackVersion: '^
|
|
47
|
+
{ name: 'typescript', fallbackVersion: '^6.0.3', minimumVersion: '6.0.0', prefix: '^' },
|
|
48
|
+
// TS7 native compiler for ttsc (TTSC_TSGO_BINARY). Not the unscoped API package.
|
|
49
|
+
// npm alias form required — Bun cannot install @typescript/typescript6 cleanly (bun#33834).
|
|
50
|
+
{ name: '@typescript/native', fallbackVersion: 'npm:typescript@^7.0.2' },
|
|
41
51
|
];
|
|
42
52
|
const cliPackageName = '@smoothbricks/cli';
|
|
43
53
|
const requiredDevenvPackages = ['bun', 'git', 'git-format-staged', 'jq', 'alejandra', 'coreutils', 'gnutar'];
|
|
@@ -46,15 +56,18 @@ const requiredDevenvPackages = ['bun', 'git', 'git-format-staged', 'jq', 'alejan
|
|
|
46
56
|
// with the runtime is validated against the live PATH (validateRootRuntimeVersions),
|
|
47
57
|
// never against a version template here.
|
|
48
58
|
const nodePackagePattern = /(^|\s)nodejs(_\d+|_latest)?(\s|#|$)/m;
|
|
59
|
+
const TTSC_PATCHED_DEPENDENCY_KEY = 'ttsc@0.19.3';
|
|
60
|
+
const TTSC_PATCH_PATH = 'patches/ttsc@0.19.3.patch';
|
|
49
61
|
export async function applyToolConfigDefaults(root) {
|
|
50
|
-
const context = readToolContext(root);
|
|
62
|
+
const context = await readToolContext(root);
|
|
51
63
|
await applyRootPackageToolDefaults(root, context);
|
|
52
64
|
applyToolingPackageDefaults(root, context.policy);
|
|
53
65
|
applyDevenvPackageDefaults(root);
|
|
54
66
|
}
|
|
55
|
-
export function validateToolConfig(root) {
|
|
56
|
-
const context = readToolContext(root);
|
|
67
|
+
export async function validateToolConfig(root) {
|
|
68
|
+
const context = await readToolContext(root);
|
|
57
69
|
return (validateRootDevDependencies(context.policy, context.rootPackage) +
|
|
70
|
+
validateTtscPatchedDependency(context.rootPackage) +
|
|
58
71
|
validateToolingPackage(root, context.policy) +
|
|
59
72
|
validateToolingWorkspace(context.rootPackage) +
|
|
60
73
|
validateDevenvPackages(root));
|
|
@@ -76,6 +89,7 @@ export async function applyRootDevDependencyDefaults(root, context) {
|
|
|
76
89
|
if (delete devDependencies['@smoothbricks/cli']) {
|
|
77
90
|
changed = true;
|
|
78
91
|
}
|
|
92
|
+
changed = ensureTtscPatchedDependency(pkg) || changed;
|
|
79
93
|
if (changed) {
|
|
80
94
|
writeJsonObject(join(root, 'package.json'), pkg);
|
|
81
95
|
console.log('updated package.json workspace tool dependencies');
|
|
@@ -91,6 +105,7 @@ async function applyRootPackageToolDefaults(root, context) {
|
|
|
91
105
|
}
|
|
92
106
|
let dependencyChanged = false;
|
|
93
107
|
let workspaceChanged = false;
|
|
108
|
+
let patchChanged = false;
|
|
94
109
|
const devDependencies = ensureDependencyMap(pkg, 'devDependencies');
|
|
95
110
|
for (const dependency of rootDevDependencies) {
|
|
96
111
|
const current = devDependencies[dependency.name];
|
|
@@ -103,7 +118,8 @@ async function applyRootPackageToolDefaults(root, context) {
|
|
|
103
118
|
dependencyChanged = true;
|
|
104
119
|
}
|
|
105
120
|
workspaceChanged = addWorkspacePattern(pkg, 'tooling');
|
|
106
|
-
|
|
121
|
+
patchChanged = ensureTtscPatchedDependency(pkg);
|
|
122
|
+
if (dependencyChanged || workspaceChanged || patchChanged) {
|
|
107
123
|
writeJsonObject(join(root, 'package.json'), pkg);
|
|
108
124
|
}
|
|
109
125
|
console.log(dependencyChanged
|
|
@@ -112,6 +128,9 @@ async function applyRootPackageToolDefaults(root, context) {
|
|
|
112
128
|
console.log(workspaceChanged
|
|
113
129
|
? 'updated package.json tooling workspace'
|
|
114
130
|
: 'unchanged package.json tooling workspace');
|
|
131
|
+
console.log(patchChanged
|
|
132
|
+
? 'updated package.json patchedDependencies for ttsc'
|
|
133
|
+
: 'unchanged package.json patchedDependencies for ttsc');
|
|
115
134
|
}
|
|
116
135
|
export function applyToolingPackageDefaults(root, policy) {
|
|
117
136
|
const path = join(root, 'tooling', 'package.json');
|
|
@@ -200,6 +219,22 @@ export function validateRootDevDependencies(policy, rootPackage) {
|
|
|
200
219
|
}
|
|
201
220
|
return failures;
|
|
202
221
|
}
|
|
222
|
+
function ensureTtscPatchedDependency(pkg) {
|
|
223
|
+
const patched = ensureDependencyMap(pkg, 'patchedDependencies');
|
|
224
|
+
return setStringProperty(patched, TTSC_PATCHED_DEPENDENCY_KEY, TTSC_PATCH_PATH);
|
|
225
|
+
}
|
|
226
|
+
function validateTtscPatchedDependency(rootPackage) {
|
|
227
|
+
if (!rootPackage) {
|
|
228
|
+
return 0;
|
|
229
|
+
}
|
|
230
|
+
const actual = rootPackage.patchedDependencies?.[TTSC_PATCHED_DEPENDENCY_KEY];
|
|
231
|
+
if (actual === TTSC_PATCH_PATH) {
|
|
232
|
+
return 0;
|
|
233
|
+
}
|
|
234
|
+
console.error(`package.json patchedDependencies.${TTSC_PATCHED_DEPENDENCY_KEY} must be ${TTSC_PATCH_PATH}` +
|
|
235
|
+
(typeof actual === 'string' ? `; found ${actual}` : ' (required for declaration-emit fix)'));
|
|
236
|
+
return 1;
|
|
237
|
+
}
|
|
203
238
|
export function validateToolingPackage(root, policy) {
|
|
204
239
|
const path = join(root, 'tooling', 'package.json');
|
|
205
240
|
const pkg = readJsonObject(path);
|
|
@@ -287,6 +322,10 @@ function satisfiesDependencyPolicy(policy, version, dependency) {
|
|
|
287
322
|
if (workspaceDependencyExpected(policy, dependency)) {
|
|
288
323
|
return version === 'workspace:*';
|
|
289
324
|
}
|
|
325
|
+
// Dual-package native compiler: must stay an npm:typescript@7 alias, never unscoped "typescript".
|
|
326
|
+
if (dependency.name === '@typescript/native') {
|
|
327
|
+
return isTypeScriptNativeAlias(version);
|
|
328
|
+
}
|
|
290
329
|
if (dependency.minimumVersion === undefined) {
|
|
291
330
|
return version === dependency.fallbackVersion;
|
|
292
331
|
}
|
|
@@ -297,34 +336,38 @@ function satisfiesDependencyPolicy(policy, version, dependency) {
|
|
|
297
336
|
}
|
|
298
337
|
return compareVersions(parsed, minimum) >= 0;
|
|
299
338
|
}
|
|
339
|
+
function isTypeScriptNativeAlias(version) {
|
|
340
|
+
// Accept npm:typescript@7, npm:typescript@^7.0.2, npm:typescript@~7.0.2, etc.
|
|
341
|
+
return /^npm:typescript@(?:\^|~)?7(?:\.|$)/.test(version.trim());
|
|
342
|
+
}
|
|
300
343
|
function formatExpectedDependency(policy, dependency) {
|
|
301
344
|
if (workspaceDependencyExpected(policy, dependency)) {
|
|
302
345
|
return 'workspace:*';
|
|
303
346
|
}
|
|
347
|
+
if (dependency.name === '@typescript/native') {
|
|
348
|
+
return 'npm:typescript@^7 (TypeScript 7 native compiler alias for ttsc)';
|
|
349
|
+
}
|
|
304
350
|
return dependency.minimumVersion ? `>= ${dependency.minimumVersion}` : dependency.fallbackVersion;
|
|
305
351
|
}
|
|
306
|
-
export function readToolContext(root) {
|
|
352
|
+
export async function readToolContext(root) {
|
|
307
353
|
const rootPackage = readPackageJsonObject(join(root, 'package.json'));
|
|
308
354
|
const toolingPackage = readJsonObject(join(root, 'tooling', 'package.json'));
|
|
309
355
|
const configuredCliRange = toolingPackage?.dependencies?.[cliPackageName];
|
|
310
356
|
return {
|
|
311
357
|
rootPackage,
|
|
312
|
-
policy: toolPolicy(rootPackage, typeof configuredCliRange === 'string' ? configuredCliRange : null),
|
|
358
|
+
policy: await toolPolicy(rootPackage, typeof configuredCliRange === 'string' ? configuredCliRange : null),
|
|
313
359
|
};
|
|
314
360
|
}
|
|
315
|
-
function toolPolicy(rootPackage, configuredCliRange) {
|
|
361
|
+
async function toolPolicy(rootPackage, configuredCliRange) {
|
|
316
362
|
const name = rootPackage?.name ?? null;
|
|
317
363
|
const isCodebase = isSmoothBricksCodebasePackageName(name ?? undefined);
|
|
318
364
|
const toolingName = toolingPackageName(name);
|
|
319
|
-
// A locally linked prerelease can be newer than every published CLI. Keep an existing
|
|
320
|
-
// installable range instead of rewriting the consumer manifest to an unpublished version.
|
|
321
|
-
const publishedCliRange = cliPackageVersion.includes('-') && configuredCliRange && parseVersion(configuredCliRange)
|
|
322
|
-
? configuredCliRange
|
|
323
|
-
: `^${cliPackageVersion}`;
|
|
324
365
|
return {
|
|
325
366
|
isSmoothBricksCodebase: isCodebase,
|
|
326
367
|
toolingPackageName: toolingName,
|
|
327
|
-
|
|
368
|
+
// Consumers pin the latest *published* CLI. Running a linked prerelease must not
|
|
369
|
+
// freeze tooling/package.json on an older range or rewrite it to an unpublished -next.
|
|
370
|
+
cliDependencyRange: isCodebase ? 'workspace:*' : await resolvePublishedCliDependencyRange(configuredCliRange),
|
|
328
371
|
};
|
|
329
372
|
}
|
|
330
373
|
function toolingPackageName(rootName) {
|
|
@@ -345,6 +388,57 @@ async function resolveDependencyVersion(policy, dependency) {
|
|
|
345
388
|
const latest = await fetchLatestPatchVersion(dependency.name, dependency.minimumVersion);
|
|
346
389
|
return `${dependency.prefix ?? ''}${latest ?? stripRangePrefix(dependency.fallbackVersion)}`;
|
|
347
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* Consumer monorepos pin `@smoothbricks/cli` to the latest stable release.
|
|
393
|
+
* Prefer npm `dist-tags.latest`. Never write a running `-next` package version into
|
|
394
|
+
* consumer manifests; never leave an older pin just because the running CLI is prerelease.
|
|
395
|
+
*/
|
|
396
|
+
async function resolvePublishedCliDependencyRange(configuredCliRange) {
|
|
397
|
+
const latest = await fetchLatestStableVersion(cliPackageName);
|
|
398
|
+
if (latest) {
|
|
399
|
+
return `^${latest}`;
|
|
400
|
+
}
|
|
401
|
+
// Registry unavailable: if the running CLI is a stable publish, use it.
|
|
402
|
+
if (!cliPackageVersion.includes('-')) {
|
|
403
|
+
return `^${cliPackageVersion}`;
|
|
404
|
+
}
|
|
405
|
+
// Linked prerelease + offline down: keep an existing installable stable pin.
|
|
406
|
+
if (configuredCliRange && parseVersion(configuredCliRange)) {
|
|
407
|
+
return configuredCliRange;
|
|
408
|
+
}
|
|
409
|
+
// Last resort: caret of the prerelease base (0.10.5-next.0 → ^0.10.5) so manifests stay valid.
|
|
410
|
+
const base = parseVersion(cliPackageVersion);
|
|
411
|
+
return base ? `^${base.major}.${base.minor}.${base.patch}` : `^${cliPackageVersion}`;
|
|
412
|
+
}
|
|
413
|
+
async function fetchLatestStableVersion(packageName) {
|
|
414
|
+
const url = `https://registry.npmjs.org/${encodeURIComponent(packageName).replace('%40', '@')}`;
|
|
415
|
+
const response = await fetch(url, { headers: { accept: 'application/vnd.npm.install-v1+json' } });
|
|
416
|
+
if (!response.ok) {
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
const body = await response.json();
|
|
420
|
+
if (!isRegistryPackument(body)) {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
const tagged = body['dist-tags']?.latest;
|
|
424
|
+
if (typeof tagged === 'string' && parseVersion(tagged) && !tagged.includes('-')) {
|
|
425
|
+
return tagged;
|
|
426
|
+
}
|
|
427
|
+
let latest = null;
|
|
428
|
+
for (const raw of Object.keys(body.versions)) {
|
|
429
|
+
if (raw.includes('-')) {
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
const version = parseVersion(raw);
|
|
433
|
+
if (!version) {
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
if (!latest || compareVersions(version, latest) > 0) {
|
|
437
|
+
latest = version;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return latest ? `${latest.major}.${latest.minor}.${latest.patch}` : null;
|
|
441
|
+
}
|
|
348
442
|
async function fetchLatestPatchVersion(packageName, minimumVersion) {
|
|
349
443
|
const minorRange = sameMajorMinorRange(minimumVersion);
|
|
350
444
|
const url = `https://registry.npmjs.org/${encodeURIComponent(packageName).replace('%40', '@')}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/release/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/release/index.ts"],"names":[],"mappings":"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"}
|
package/dist/release/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { withDevenvEnv } from '../lib/devenv.js';
|
|
|
12
12
|
import { parseNxJsonText, parseNxProjectJsonText, parsePackageJsonText, } from '../lib/json.js';
|
|
13
13
|
import { decode, run, runInteractiveStatus, runResult } from '../lib/run.js';
|
|
14
14
|
import { listReleasePackages, readPackageJson, repositoryInfo } from '../lib/workspace.js';
|
|
15
|
+
import { syncBunLockfileVersions } from '../monorepo/lockfile.js';
|
|
15
16
|
import { readPackedPackageJson, validatePackedWorkspaceDependencies } from '../monorepo/packed-manifest.js';
|
|
16
17
|
import { bootstrapNpmPackages, NPM_BOOTSTRAP_DIST_TAG, NPM_BOOTSTRAP_VERSION, } from './bootstrap-npm-packages.js';
|
|
17
18
|
import { autoReleaseCandidatePackages } from './candidates.js';
|
|
@@ -301,6 +302,10 @@ async function listUnpublishedPackages(root, packages) {
|
|
|
301
302
|
async function publishPackedPackage(root, pkg, tag, dryRun) {
|
|
302
303
|
const tempDir = await mkdtemp(join(tmpdir(), 'smoo-publish-'));
|
|
303
304
|
const tarball = join(tempDir, `${safeTarballPrefix(pkg.name)}-${pkg.version}.tgz`);
|
|
305
|
+
// bun pm pack resolves workspace:* from bun.lock. Day-to-day lock keeps -next
|
|
306
|
+
// (install/CI). For publish, temporarily rewrite unpublished -next entries to
|
|
307
|
+
// the last stable tag so the tarball embeds installable versions, then restore.
|
|
308
|
+
syncBunLockfileVersions(root, { mode: 'publish', log: true });
|
|
304
309
|
try {
|
|
305
310
|
console.log(`${pkg.name}@${pkg.version}: packing with bun pm pack`);
|
|
306
311
|
await run('bun', ['pm', 'pack', '--filename', tarball, '--ignore-scripts', '--quiet'], join(root, pkg.path));
|
|
@@ -329,6 +334,7 @@ async function publishPackedPackage(root, pkg, tag, dryRun) {
|
|
|
329
334
|
});
|
|
330
335
|
}
|
|
331
336
|
finally {
|
|
337
|
+
syncBunLockfileVersions(root, { mode: 'install', log: true });
|
|
332
338
|
await rm(tempDir, { recursive: true, force: true });
|
|
333
339
|
}
|
|
334
340
|
}
|
package/managed/raw/envrc
CHANGED
|
@@ -11,8 +11,10 @@ esac
|
|
|
11
11
|
|
|
12
12
|
watch_file tooling/direnv/envrc.sh
|
|
13
13
|
|
|
14
|
+
# Load local extensions and overrides from the project root (the gitignored
|
|
15
|
+
# .envrc-local); capture it before we cd into tooling/direnv, since envrc.sh
|
|
16
|
+
# leaves us there and a bare relative path would resolve under tooling/direnv.
|
|
17
|
+
local_override="$PWD/.envrc-local"
|
|
14
18
|
cd tooling/direnv
|
|
15
19
|
. envrc.sh
|
|
16
|
-
|
|
17
|
-
# Load local extensions and overrides
|
|
18
|
-
source_env_if_exists .envrc-local
|
|
20
|
+
source_env_if_exists "$local_override"
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
--- a/driver/emit_plugin.go
|
|
2
|
+
+++ b/driver/emit_plugin.go
|
|
3
|
+
@@ -163,6 +163,32 @@
|
|
4
|
+
}
|
|
5
|
+
host := &pluginEmitHost{program: p.TSProgram, emitResolver: p.Checker.GetEmitResolver()}
|
|
6
|
+
options := p.TSProgram.Options()
|
|
7
|
+
+ // Declaration emit must observe the original program before plugin transforms
|
|
8
|
+
+ // can mutate source-file nodes while assembling JavaScript output.
|
|
9
|
+
+ if options.GetEmitDeclarations() {
|
|
10
|
+
+ var wfMu sync.Mutex
|
|
11
|
+
+ result := p.TSProgram.Emit(context.Background(), shimcompiler.EmitOptions{
|
|
12
|
+
+ EmitOnly: shimcompiler.EmitOnlyDts,
|
|
13
|
+
+ WriteFile: func(fileName string, text string, data *shimcompiler.WriteFileData) error {
|
|
14
|
+
+ wfMu.Lock()
|
|
15
|
+
+ defer wfMu.Unlock()
|
|
16
|
+
+ if p.outputEscapesOutDir(fileName) {
|
|
17
|
+
+ if data != nil {
|
|
18
|
+
+ data.SkippedDtsWrite = true
|
|
19
|
+
+ }
|
|
20
|
+
+ return nil
|
|
21
|
+
+ }
|
|
22
|
+
+ if writeFile != nil {
|
|
23
|
+
+ return writeFile(fileName, text, data)
|
|
24
|
+
+ }
|
|
25
|
+
+ return DefaultWriteFile(fileName, text)
|
|
26
|
+
+ },
|
|
27
|
+
+ })
|
|
28
|
+
+ if result != nil && len(result.Diagnostics) != 0 {
|
|
29
|
+
+ return convertDiagnostics(result.Diagnostics), nil
|
|
30
|
+
+ }
|
|
31
|
+
+ }
|
|
32
|
+
+
|
|
33
|
+
for _, sf := range shimcompiler.GetSourceFilesToEmit(host, nil, false) {
|
|
34
|
+
paths := shimcompiler.GetOutputPathsFor(sf, options, host, false)
|
|
35
|
+
if paths.JsFilePath() != "" && !p.outputEscapesOutDir(paths.JsFilePath()) {
|
|
36
|
+
@@ -212,31 +238,6 @@
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
- if !options.GetEmitDeclarations() {
|
|
41
|
+
- return nil, nil
|
|
42
|
+
- }
|
|
43
|
+
-
|
|
44
|
+
- var wfMu sync.Mutex
|
|
45
|
+
- result := p.TSProgram.Emit(context.Background(), shimcompiler.EmitOptions{
|
|
46
|
+
- EmitOnly: shimcompiler.EmitOnlyDts,
|
|
47
|
+
- WriteFile: func(fileName string, text string, data *shimcompiler.WriteFileData) error {
|
|
48
|
+
- wfMu.Lock()
|
|
49
|
+
- defer wfMu.Unlock()
|
|
50
|
+
- if p.outputEscapesOutDir(fileName) {
|
|
51
|
+
- if data != nil {
|
|
52
|
+
- data.SkippedDtsWrite = true
|
|
53
|
+
- }
|
|
54
|
+
- return nil
|
|
55
|
+
- }
|
|
56
|
+
- if writeFile != nil {
|
|
57
|
+
- return writeFile(fileName, text, data)
|
|
58
|
+
- }
|
|
59
|
+
- return DefaultWriteFile(fileName, text)
|
|
60
|
+
- },
|
|
61
|
+
- })
|
|
62
|
+
- if result != nil && len(result.Diagnostics) != 0 {
|
|
63
|
+
- return convertDiagnostics(result.Diagnostics), nil
|
|
64
|
+
- }
|
|
65
|
+
return nil, nil
|
|
66
|
+
}
|
|
67
|
+
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
#!/bin/bash
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
4
|
NIX_STORE_NAR="${NIX_STORE_NAR:-/tmp/nix-store.nar}"
|
|
5
5
|
nix_store_cmd="/nix/var/nix/profiles/default/bin/nix-store"
|
|
6
|
+
DEVENV_FLAKE="${DEVENV_FLAKE:-github:cachix/devenv}"
|
|
7
|
+
# Host CI cache (GARM bind-mount). Prefer env from runner profile.
|
|
8
|
+
# Path comes from the runner (GARM profile). Ephemeral runners leave unset;
|
|
9
|
+
# devenv enterShell defaults to $PWD/.cache/ttsc.
|
|
10
|
+
TTSC_CACHE_DIR="${TTSC_CACHE_DIR:-}"
|
|
6
11
|
# Resolve from this script's location, not the caller's cwd. GitHub Actions
|
|
7
12
|
# runs this from tooling/direnv today, but direct cwd-changing helpers are easy
|
|
8
13
|
# to misuse and break on repeated calls.
|
|
@@ -36,12 +41,21 @@ restore_nix_store() {
|
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
install_devenv() {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
# Shared host /nix/store is the package cache. Image may already provide
|
|
45
|
+
# devenv from github:cachix/devenv; otherwise profile-add the same flake
|
|
46
|
+
# (links store paths; re-fetch only when missing).
|
|
47
|
+
if command -v devenv >/dev/null 2>&1; then
|
|
48
|
+
echo "using existing devenv: $(command -v devenv) ($(devenv version 2>/dev/null || true))"
|
|
49
|
+
else
|
|
50
|
+
echo "nix profile add ${DEVENV_FLAKE}"
|
|
51
|
+
nix profile add --accept-flake-config "$DEVENV_FLAKE"
|
|
52
|
+
fi
|
|
53
|
+
if [ -d "$HOME/.nix-profile/bin" ]; then
|
|
54
|
+
echo "$HOME/.nix-profile/bin" >> "${GITHUB_PATH:-/dev/null}"
|
|
55
|
+
fi
|
|
56
|
+
if [ -n "$TTSC_CACHE_DIR" ]; then
|
|
57
|
+
mkdir -p "$TTSC_CACHE_DIR"
|
|
42
58
|
fi
|
|
43
|
-
echo "$HOME/.nix-profile/bin" >> "$GITHUB_PATH"
|
|
44
|
-
sudo ln -sf "$HOME/.nix-profile" /nix/var/nix/gcroots/ci/profile
|
|
45
59
|
}
|
|
46
60
|
|
|
47
61
|
build_devenv_shell() {
|
|
@@ -50,7 +64,10 @@ build_devenv_shell() {
|
|
|
50
64
|
# independent workflow step shells that run after this composite action.
|
|
51
65
|
if [ -n "${GITHUB_ENV:-}" ]; then
|
|
52
66
|
echo "TTSC_TSGO_BINARY=$repo_root/node_modules/@typescript/native/bin/tsc" >> "$GITHUB_ENV"
|
|
53
|
-
|
|
67
|
+
# Only re-export when the runner (or a prior step) already set the path.
|
|
68
|
+
if [ -n "$TTSC_CACHE_DIR" ]; then
|
|
69
|
+
echo "TTSC_CACHE_DIR=$TTSC_CACHE_DIR" >> "$GITHUB_ENV"
|
|
70
|
+
fi
|
|
54
71
|
fi
|
|
55
72
|
# Add repo-local tools only after the shell exists; cleanup steps use an
|
|
56
73
|
# explicit PATH because failures before this point must still refresh caches.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { existsSync, mkdirSync, readdirSync, readlinkSync, rmSync, symlinkSync } from 'node:fs';
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, readlinkSync, rmSync, symlinkSync } from 'node:fs';
|
|
3
3
|
import { mkdir, rmdir, stat } from 'node:fs/promises';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import path from 'node:path';
|
|
@@ -98,8 +98,28 @@ function ensureTypeScriptApiPackage(root: string): void {
|
|
|
98
98
|
assertTypescriptApiAt(path.join(root, 'node_modules', '.bun', 'node_modules', 'typescript'), apiPackageRoot);
|
|
99
99
|
|
|
100
100
|
const nativeBin = path.join(root, 'node_modules', '@typescript', 'native', 'bin', 'tsc');
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
const rootPackageJson = path.join(root, 'package.json');
|
|
102
|
+
const declaresNative =
|
|
103
|
+
existsSync(rootPackageJson) &&
|
|
104
|
+
(() => {
|
|
105
|
+
try {
|
|
106
|
+
const pkg = JSON.parse(readFileSync(rootPackageJson, 'utf8')) as {
|
|
107
|
+
devDependencies?: Record<string, string>;
|
|
108
|
+
dependencies?: Record<string, string>;
|
|
109
|
+
};
|
|
110
|
+
return (
|
|
111
|
+
typeof pkg.devDependencies?.['@typescript/native'] === 'string' ||
|
|
112
|
+
typeof pkg.dependencies?.['@typescript/native'] === 'string'
|
|
113
|
+
);
|
|
114
|
+
} catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
})();
|
|
118
|
+
if (declaresNative && !existsSync(nativeBin)) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`Missing ${nativeBin}. package.json declares @typescript/native but it is not installed. ` +
|
|
121
|
+
'Run bun install (or direnv reload). @typescript/native is the TypeScript 7 native compiler for ttsc.',
|
|
122
|
+
);
|
|
103
123
|
}
|
|
104
124
|
}
|
|
105
125
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
name: Cache Nix profiles, devenv and direnv
|
|
2
|
-
description:
|
|
2
|
+
description: >
|
|
3
|
+
Two independent segments: large nix (NAR/profiles, ephemeral runners only) and small devenv (.devenv/.direnv — eval
|
|
4
|
+
SQLite, shell scripts, profile; all runners).
|
|
3
5
|
|
|
4
6
|
inputs:
|
|
5
7
|
segment:
|
|
@@ -19,12 +21,11 @@ outputs:
|
|
|
19
21
|
runs:
|
|
20
22
|
using: composite
|
|
21
23
|
steps:
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
- name: Restore Nix profiles, devenv and direnv
|
|
24
|
+
# Large segment: Nix profile + exported store NAR. Ephemeral runners only.
|
|
25
|
+
# Key = shell closure inputs; direnv/setup script edits must not bust a multi-GB NAR.
|
|
26
|
+
- name: Restore Nix profiles and store NAR
|
|
26
27
|
id: restore-nix
|
|
27
|
-
if:
|
|
28
|
+
if: inputs.segment == 'nix' && inputs.mode == 'restore'
|
|
28
29
|
uses: actions/cache/restore@v5.0.5
|
|
29
30
|
with:
|
|
30
31
|
path: |
|
|
@@ -39,7 +40,7 @@ runs:
|
|
|
39
40
|
${{ runner.os }}-${{ runner.arch }}-nix-v3-
|
|
40
41
|
|
|
41
42
|
- name: Save Nix profiles and store NAR
|
|
42
|
-
if:
|
|
43
|
+
if: inputs.segment == 'nix' && inputs.mode == 'save'
|
|
43
44
|
uses: actions/cache/save@v5.0.5
|
|
44
45
|
with:
|
|
45
46
|
path: |
|
|
@@ -51,11 +52,12 @@ runs:
|
|
|
51
52
|
${{ runner.os }}-${{ runner.arch }}-nix-v3-${{ hashFiles('tooling/direnv/devenv.yaml',
|
|
52
53
|
'tooling/direnv/devenv.nix', 'tooling/direnv/devenv.lock') }}
|
|
53
54
|
|
|
54
|
-
#
|
|
55
|
-
#
|
|
55
|
+
# Small segment: devenv eval cache (nix-eval-cache.db), shell-*.sh, profile, .direnv.
|
|
56
|
+
# Own key. Setup restores on every runner; not gated on nix NAR hit. Devenv drops a
|
|
57
|
+
# shell cache row when drv/out are missing (GC) and re-evals/realizes.
|
|
56
58
|
- name: Restore devenv and direnv state
|
|
57
59
|
id: restore-devenv
|
|
58
|
-
if:
|
|
60
|
+
if: inputs.segment == 'devenv' && inputs.mode == 'restore'
|
|
59
61
|
uses: actions/cache/restore@v5.0.5
|
|
60
62
|
with:
|
|
61
63
|
path: |
|
|
@@ -69,7 +71,7 @@ runs:
|
|
|
69
71
|
${{ runner.os }}-${{ runner.arch }}-devenv-v3-
|
|
70
72
|
|
|
71
73
|
- name: Save devenv and direnv state
|
|
72
|
-
if:
|
|
74
|
+
if: inputs.segment == 'devenv' && inputs.mode == 'save'
|
|
73
75
|
uses: actions/cache/save@v5.0.5
|
|
74
76
|
with:
|
|
75
77
|
path: |
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
name: Save Nix/devenv caches
|
|
2
|
-
description:
|
|
2
|
+
description: >
|
|
3
|
+
Save cache segments after the job. Nix store NAR stays ephemeral-only (host uses shared /nix/store). Devenv/direnv
|
|
4
|
+
eval-cache segment saves on every runner when setup missed and build-shell produced nix-eval-cache.db.
|
|
3
5
|
|
|
4
6
|
inputs:
|
|
5
7
|
nix-cache-hit:
|
|
@@ -14,8 +16,19 @@ inputs:
|
|
|
14
16
|
runs:
|
|
15
17
|
using: composite
|
|
16
18
|
steps:
|
|
19
|
+
- name: 🔎 Runner kind
|
|
20
|
+
id: runner-kind
|
|
21
|
+
shell: bash
|
|
22
|
+
run: |
|
|
23
|
+
if [ "${NIX_REMOTE:-}" = daemon ] && [ -d /var/cache/ci ]; then
|
|
24
|
+
echo "host=true" >> "$GITHUB_OUTPUT"
|
|
25
|
+
else
|
|
26
|
+
echo "host=false" >> "$GITHUB_OUTPUT"
|
|
27
|
+
fi
|
|
28
|
+
|
|
17
29
|
- name: 🧹 Prepare Nix/devenv cache save
|
|
18
30
|
id: cleanup-cache
|
|
31
|
+
if: steps.runner-kind.outputs.host != 'true'
|
|
19
32
|
shell: bash
|
|
20
33
|
working-directory: tooling/direnv
|
|
21
34
|
env:
|
|
@@ -33,14 +46,32 @@ runs:
|
|
|
33
46
|
smoo github-ci cleanup-cache
|
|
34
47
|
|
|
35
48
|
- name: 🧊 Save Nix profiles and store NAR
|
|
36
|
-
if:
|
|
49
|
+
if:
|
|
50
|
+
${{ steps.runner-kind.outputs.host != 'true' && steps.cleanup-cache.outputs.cache-ready == 'true' &&
|
|
51
|
+
inputs.nix-cache-hit != 'true' }}
|
|
37
52
|
uses: ./.github/actions/cache-nix-devenv
|
|
38
53
|
with:
|
|
39
54
|
segment: nix
|
|
40
55
|
mode: save
|
|
41
56
|
|
|
57
|
+
# Devenv segment is independent of nix NAR readiness and host vs ephemeral.
|
|
58
|
+
# Skip when setup never finished (no eval DB) so if: always() cannot poison
|
|
59
|
+
# the next restore with an empty/partial key.
|
|
60
|
+
- name: 🔎 Devenv save ready
|
|
61
|
+
id: devenv-save
|
|
62
|
+
if: inputs.devenv-cache-hit != 'true'
|
|
63
|
+
shell: bash
|
|
64
|
+
run: |
|
|
65
|
+
db="${GITHUB_WORKSPACE}/tooling/direnv/.devenv/nix-eval-cache.db"
|
|
66
|
+
if [[ -f "$db" ]]; then
|
|
67
|
+
echo "ready=true" >> "$GITHUB_OUTPUT"
|
|
68
|
+
else
|
|
69
|
+
echo "ready=false" >> "$GITHUB_OUTPUT"
|
|
70
|
+
echo "skip devenv save: no nix-eval-cache.db"
|
|
71
|
+
fi
|
|
72
|
+
|
|
42
73
|
- name: 🧊 Save devenv and direnv
|
|
43
|
-
if: ${{
|
|
74
|
+
if: ${{ inputs.devenv-cache-hit != 'true' && steps.devenv-save.outputs.ready == 'true' }}
|
|
44
75
|
uses: ./.github/actions/cache-nix-devenv
|
|
45
76
|
with:
|
|
46
77
|
segment: devenv
|