From 150f2b7b0992664bce4d2418c341104690a7ff2b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 01:10:24 +0000 Subject: [PATCH 1/5] Initial plan From f922a27e996a5d4341aceb21bdbff9406edeb0a0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 01:30:26 +0000 Subject: [PATCH 2/5] Remove ts-node in favor of native Node.js TypeScript support - Remove enableTypeScript.ts and getTsNodeEnv.ts modules - Update config.ts to remove ts-node registration (Node 22.18+ handles TS natively) - Add support for detecting just.config.mjs and just.config.mts - Remove --esm CLI option (no longer needed with native TS) - Update nodeExecTask to remove ts-node options (enableTypeScript, tsconfig, transpileOnly) - Update webpack tasks to remove ts-node env setup and related options - Remove ts-node from just-example-lib devDependencies - Update example code to use import.meta.dirname instead of __dirname - Update docs to reference native Node.js TS support instead of ts-node - Add tests for new .mjs and .mts config file extensions - Update API reports Co-authored-by: ecraig12345 <5864305+ecraig12345@users.noreply.github.com> Agent-Logs-Url: https://github.com/microsoft/just/sessions/b13c48b9-2eb7-4f77-a0eb-52587b449842 --- docs/tasks/index.md | 6 +- packages/just-example-lib/just.config.ts | 2 +- packages/just-example-lib/package.json | 3 +- packages/just-example-lib/tasks/customTask.ts | 2 +- packages/just-scripts/etc/just-scripts.api.md | 8 - .../src/tasks/__tests__/nodeExecTask.test.ts | 203 ++++++++---------- .../just-scripts/src/tasks/nodeExecTask.ts | 31 +-- .../just-scripts/src/tasks/webpackCliTask.ts | 29 --- .../src/tasks/webpackDevServerTask.ts | 15 -- .../just-scripts/src/tasks/webpackTask.ts | 11 - .../src/typescript/getTsNodeEnv.ts | 21 -- .../just-task/src/__tests__/resolve.spec.ts | 119 +++++----- packages/just-task/src/cli.ts | 5 - packages/just-task/src/config.ts | 10 +- packages/just-task/src/enableTypeScript.ts | 35 --- 15 files changed, 160 insertions(+), 340 deletions(-) delete mode 100644 packages/just-scripts/src/typescript/getTsNodeEnv.ts delete mode 100644 packages/just-task/src/enableTypeScript.ts diff --git a/docs/tasks/index.md b/docs/tasks/index.md index 93f69033..90f8a622 100644 --- a/docs/tasks/index.md +++ b/docs/tasks/index.md @@ -23,13 +23,13 @@ task('sayhello', function () { ## Defining tasks in style with TypeScript -1. Install `ts-node` and `typescript`: +Node.js 22.18+ supports running TypeScript natively via [type stripping](https://nodejs.org/docs/latest-v22.x/api/typescript.html#type-stripping). Just takes advantage of this, so you only need `typescript` installed: ``` -npm i -D ts-node typescript +npm i -D typescript ``` -2. Place tasks inside `just.config.ts` in your root folder (next to package.json): +Place tasks inside `just.config.ts` in your root folder (next to package.json): ```js // ES Module style diff --git a/packages/just-example-lib/just.config.ts b/packages/just-example-lib/just.config.ts index 02b8363f..107f3f85 100644 --- a/packages/just-example-lib/just.config.ts +++ b/packages/just-example-lib/just.config.ts @@ -3,7 +3,7 @@ import { nodeExecTask, tscTask, task, parallel, watch } from 'just-scripts'; task('typescript', tscTask({})); task('typescript:watch', tscTask({ watch: true })); -task('customNodeTask', nodeExecTask({ enableTypeScript: true, args: ['./tasks/customTask.ts'] })); +task('customNodeTask', nodeExecTask({ args: ['./tasks/customTask.ts'] })); task('build', parallel('customNodeTask', 'typescript')); task('watch', parallel('typescript:watch')); diff --git a/packages/just-example-lib/package.json b/packages/just-example-lib/package.json index dd3010c0..08c1df6b 100644 --- a/packages/just-example-lib/package.json +++ b/packages/just-example-lib/package.json @@ -12,7 +12,6 @@ "node": ">=22.18.0" }, "devDependencies": { - "just-scripts": "workspace:^", - "ts-node": "^10.8.0" + "just-scripts": "workspace:^" } } diff --git a/packages/just-example-lib/tasks/customTask.ts b/packages/just-example-lib/tasks/customTask.ts index 9724df52..d2c1be6e 100644 --- a/packages/just-example-lib/tasks/customTask.ts +++ b/packages/just-example-lib/tasks/customTask.ts @@ -1,3 +1,3 @@ import * as path from 'path'; import * as fs from 'fs'; -export const packageJson = fs.readFileSync(path.join(__dirname, '../package.json'), 'utf-8'); +export const packageJson = fs.readFileSync(path.join(import.meta.dirname, '../package.json'), 'utf-8'); diff --git a/packages/just-scripts/etc/just-scripts.api.md b/packages/just-scripts/etc/just-scripts.api.md index 6666261b..676ff3a0 100644 --- a/packages/just-scripts/etc/just-scripts.api.md +++ b/packages/just-scripts/etc/just-scripts.api.md @@ -298,11 +298,8 @@ export function nodeExecTask(options: NodeExecTaskOptions): TaskFunction; // @public (undocumented) export interface NodeExecTaskOptions { args: string[]; - enableTypeScript?: boolean; env?: NodeJS.ProcessEnv; spawnOptions?: SpawnOptions; - transpileOnly?: boolean; - tsconfig?: string; } // @public (undocumented) @@ -479,8 +476,6 @@ export function webpackCliTask(options?: WebpackCliTaskOptions): TaskFunction; export interface WebpackCliTaskOptions { env?: NodeJS.ProcessEnv; nodeArgs?: string[]; - transpileOnly?: boolean; - tsconfig?: string; webpackCliArgs?: string[]; } @@ -499,8 +494,6 @@ export interface WebpackDevServerTaskOptions extends WebpackCliTaskOptions, Conf mode?: 'production' | 'development'; nodeArgs?: string[]; open?: boolean; - transpileOnly?: boolean; - tsconfig?: string; } export { webpackMerge } @@ -527,7 +520,6 @@ export interface WebpackTaskOptions extends Configuration { env?: NodeJS.ProcessEnv; onCompile?: (err: Error, stats: any) => void | Promise; outputStats?: boolean | string; - transpileOnly?: boolean; } diff --git a/packages/just-scripts/src/tasks/__tests__/nodeExecTask.test.ts b/packages/just-scripts/src/tasks/__tests__/nodeExecTask.test.ts index fed9562c..ddbe506b 100644 --- a/packages/just-scripts/src/tasks/__tests__/nodeExecTask.test.ts +++ b/packages/just-scripts/src/tasks/__tests__/nodeExecTask.test.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import { getMockScript } from '../../__tests__/getMockScript'; import { MockOutputStream } from '../../__tests__/MockOutputStream'; import * as execModule from '../../utils/exec'; -import { nodeExecTask, type NodeExecTaskOptions } from '../nodeExecTask'; +import { nodeExecTask } from '../nodeExecTask'; import { callTaskForTest } from './callTaskForTest'; import { getNormalizedSpawnArgs } from './getNormalizedSpawnArgs'; @@ -32,127 +32,98 @@ describe('nodeExecTask', () => { jest.restoreAllMocks(); }); - describe.each(['javascript', 'typescript (ts-node)'])('%s', fileType => { - const isTS = fileType !== 'javascript'; - const ext = isTS ? 'ts' : 'js'; - const maybeTsAutoArgs = isTS ? ['-r', '${repoRoot}/node_modules/ts-node/register/index.js'] : []; - - /** Include appropriate TypeScript options with the task if needed */ - function wrapNodeExecTask(options: NodeExecTaskOptions) { - return nodeExecTask({ - ...(isTS && { enableTypeScript: true, transpileOnly: true }), - ...options, - }); - } - - /** Wrap a test that should be successful with extra logging in case it fails */ - async function wrapCallTask(task: TaskFunction, options?: { expectError?: boolean }) { - try { - await callTaskForTest(task); - } catch (error) { - if (options?.expectError) { - throw error; - } - // Child process failures are really hard to debug without this extra info - // (it could be because something went wrong with passing options/env) - fail( - [ - `Unexpected task failure: ${error}`, - `options: ${JSON.stringify(spawnSpy.mock.calls[0]?.[2], null, 2)}`, - 'stdout:', - stdout.getOutput(), - 'stderr:', - stderr.getOutput(), - ].join('\n'), - ); - } - if (options?.expectError) { - fail('should have thrown'); - } - } - - // These tests get expensive due to the IPC and especially with ts-node, so combine the basic - // success cases (args, default env) - it('runs a script', async () => { - const task = wrapNodeExecTask({ - args: ['--max-old-space-size=4096', getMockScript(`mock-success.${ext}`), '--', 'arg1', 'arg2'], - }); - await wrapCallTask(task); - - expect(getNormalizedSpawnArgs(spawnSpy)).toEqual([ - '${nodeExecPath}', - ...maybeTsAutoArgs, - '--max-old-space-size=4096', - `\${packageRoot}/src/__tests__/mock-success.${ext}`, - '--', - 'arg1', - 'arg2', - ]); - - const output = stdout.getOutput(); - expect(output).toContain('hello -- arg1 arg2\n'); - // Full process.env should be passed through to the script by default. - // Just verify one value we expect to be present. - expect(process.env.JEST_WORKER_ID).toBeTruthy(); - expect(output).toContain(`JEST_WORKER_ID=${process.env.JEST_WORKER_ID}`); - - if (isTS) { - expect(output).toContain('TS_NODE_'); - } else { - expect(output).not.toContain('TS_NODE_'); - } + // These tests get expensive due to the IPC, so combine the basic success cases (args, default env) + it('runs a script', async () => { + const task = nodeExecTask({ + args: ['--max-old-space-size=4096', getMockScript('mock-success.js'), '--', 'arg1', 'arg2'], }); + await wrapCallTask(task); + + expect(getNormalizedSpawnArgs(spawnSpy)).toEqual([ + '${nodeExecPath}', + '--max-old-space-size=4096', + `\${packageRoot}/src/__tests__/mock-success.js`, + '--', + 'arg1', + 'arg2', + ]); + + const output = stdout.getOutput(); + expect(output).toContain('hello -- arg1 arg2\n'); + // Full process.env should be passed through to the script by default. + // Just verify one value we expect to be present. + expect(process.env.JEST_WORKER_ID).toBeTruthy(); + expect(output).toContain(`JEST_WORKER_ID=${process.env.JEST_WORKER_ID}`); + }); - it('handles a script that fails', async () => { - const task = wrapNodeExecTask({ - args: [getMockScript(`mock-fail.${ext}`)], - }); - try { - await wrapCallTask(task, { expectError: true }); - } catch (error) { - expect((error as Error).message).toContain('Command failed'); - expect((error as any).code).toBe(1); - // in the debugger there are some extra stderr chunks - expect(stderr.getOutput()).toContain('oh no\n'); - } + it('handles a script that fails', async () => { + const task = nodeExecTask({ + args: [getMockScript('mock-fail.js')], }); + try { + await wrapCallTask(task, { expectError: true }); + } catch (error) { + expect((error as Error).message).toContain('Command failed'); + expect((error as any).code).toBe(1); + // in the debugger there are some extra stderr chunks + expect(stderr.getOutput()).toContain('oh no\n'); + } + }); - it('passes specified env only', async () => { - const task = wrapNodeExecTask({ - args: [getMockScript(`mock-success.${ext}`)], - env: { FOO: 'foo value', BAR: 'bar value' }, - }); - await wrapCallTask(task); - - const output = stdout.getOutput(); - // can't strictly check due to OS-injected values - expect(output).toContain('FOO=foo value'); - expect(output).toContain('BAR=bar value'); - // verify a value we expect to be present in the current process isn't passed through - expect(process.env.JEST_WORKER_ID).toBeTruthy(); - expect(output).not.toContain('JEST_WORKER_ID'); - - // In TS it would have failed if these were missed, but check anyway - if (isTS) { - expect(output).toContain('TS_NODE_'); - } else { - expect(output).not.toContain('TS_NODE_'); - } + it('passes specified env only', async () => { + const task = nodeExecTask({ + args: [getMockScript('mock-success.js')], + env: { FOO: 'foo value', BAR: 'bar value' }, }); + await wrapCallTask(task); + + const output = stdout.getOutput(); + // can't strictly check due to OS-injected values + expect(output).toContain('FOO=foo value'); + expect(output).toContain('BAR=bar value'); + // verify a value we expect to be present in the current process isn't passed through + expect(process.env.JEST_WORKER_ID).toBeTruthy(); + expect(output).not.toContain('JEST_WORKER_ID'); + }); - it('errors if file not found', async () => { - const script = path.join(__dirname, `nope.${ext}`); - const task = wrapNodeExecTask({ - args: [script], - }); - try { - await wrapCallTask(task, { expectError: true }); - } catch (error) { - expect((error as Error).message).toContain('Command failed'); - expect((error as any).code).toBe(1); - const output = stderr.getOutput(); - expect(output).toContain('Error: Cannot find module'); - } + it('errors if file not found', async () => { + const script = path.join(__dirname, 'nope.js'); + const task = nodeExecTask({ + args: [script], }); + try { + await wrapCallTask(task, { expectError: true }); + } catch (error) { + expect((error as Error).message).toContain('Command failed'); + expect((error as any).code).toBe(1); + const output = stderr.getOutput(); + expect(output).toContain('Error: Cannot find module'); + } }); + + /** Wrap a test that should be successful with extra logging in case it fails */ + async function wrapCallTask(task: TaskFunction, options?: { expectError?: boolean }) { + try { + await callTaskForTest(task); + } catch (error) { + if (options?.expectError) { + throw error; + } + // Child process failures are really hard to debug without this extra info + // (it could be because something went wrong with passing options/env) + fail( + [ + `Unexpected task failure: ${error}`, + `options: ${JSON.stringify(spawnSpy.mock.calls[0]?.[2], null, 2)}`, + 'stdout:', + stdout.getOutput(), + 'stderr:', + stderr.getOutput(), + ].join('\n'), + ); + } + if (options?.expectError) { + fail('should have thrown'); + } + } }); diff --git a/packages/just-scripts/src/tasks/nodeExecTask.ts b/packages/just-scripts/src/tasks/nodeExecTask.ts index 645b9fa1..dbb3eff1 100644 --- a/packages/just-scripts/src/tasks/nodeExecTask.ts +++ b/packages/just-scripts/src/tasks/nodeExecTask.ts @@ -1,8 +1,6 @@ import { SpawnOptions } from 'child_process'; import { spawn } from '../utils'; import { logger, TaskFunction } from 'just-task'; -import { resolveCwd, _tryResolve } from 'just-task/lib/resolve'; -import { getTsNodeEnv } from '../typescript/getTsNodeEnv'; export interface NodeExecTaskOptions { /** @@ -20,21 +18,6 @@ export interface NodeExecTaskOptions { */ env?: NodeJS.ProcessEnv; - /** - * Whether to use `ts-node` to execute the script - */ - enableTypeScript?: boolean; - - /** - * tsconfig file path to pass to `ts-node` - */ - tsconfig?: string; - - /** - * Whether to use `transpileOnly` mode for `ts-node` - */ - transpileOnly?: boolean; - /** * Custom spawn options. * @@ -53,23 +36,15 @@ export interface NodeExecTaskOptions { */ export function nodeExecTask(options: NodeExecTaskOptions): TaskFunction { return function () { - const { spawnOptions, enableTypeScript, tsconfig, transpileOnly } = options; + const { spawnOptions } = options; - const tsNodeRegister = resolveCwd('ts-node/register'); const nodeExecPath = process.execPath; const args = [...(options.args || [])]; // Preserve the default behavior of inheriting process.env if no options are specified - let env = options.env ? { ...options.env } : { ...process.env }; - const isTS = enableTypeScript && tsNodeRegister; - - if (isTS) { - args.unshift('-r', tsNodeRegister); - - env = { ...env, ...getTsNodeEnv(tsconfig, transpileOnly) }; - } + const env = options.env ? { ...options.env } : { ...process.env }; - logger.info([`Executing${isTS ? ' [TS]' : ''}:`, nodeExecPath, ...args].join(' ')); + logger.info(['Executing:', nodeExecPath, ...args].join(' ')); return spawn(nodeExecPath, args, { stdio: 'inherit', env, ...spawnOptions }); }; diff --git a/packages/just-scripts/src/tasks/webpackCliTask.ts b/packages/just-scripts/src/tasks/webpackCliTask.ts index b0ad7806..9affe72b 100644 --- a/packages/just-scripts/src/tasks/webpackCliTask.ts +++ b/packages/just-scripts/src/tasks/webpackCliTask.ts @@ -1,7 +1,5 @@ import { logger, TaskFunction, resolve } from 'just-task'; import { logNodeCommand, spawn } from '../utils'; -import { getTsNodeEnv } from '../typescript/getTsNodeEnv'; -import { findWebpackConfig } from '../webpack/findWebpackConfig'; export interface WebpackCliTaskOptions { /** @@ -19,16 +17,6 @@ export interface WebpackCliTaskOptions { * Environment variables to be passed to the webpack-cli */ env?: NodeJS.ProcessEnv; - - /** - * The tsconfig file to pass to ts-node for Typescript config - */ - tsconfig?: string; - - /** - * Transpile the config only - */ - transpileOnly?: boolean; } /** @@ -50,23 +38,6 @@ export function webpackCliTask(options: WebpackCliTaskOptions = {}): TaskFunctio ...(options && options.webpackCliArgs ? options.webpackCliArgs : []), ]; - let configPath = findWebpackConfig('webpack.config.js'); - - if (configPath) { - options.env = { - ...options.env, - ...(configPath.endsWith('.ts') && getTsNodeEnv(options.tsconfig, options.transpileOnly)), - }; - } - - if (options.webpackCliArgs) { - const configIndex = options.webpackCliArgs.indexOf('--config'); - const configPathAvailable = configIndex > -1 && options.webpackCliArgs.length > configIndex + 2; - if (configPathAvailable) { - configPath = options.webpackCliArgs[configIndex + 1]; - } - } - logNodeCommand(args); return spawn(process.execPath, args, { stdio: 'inherit', env: options.env }); diff --git a/packages/just-scripts/src/tasks/webpackDevServerTask.ts b/packages/just-scripts/src/tasks/webpackDevServerTask.ts index 514b1ce6..b802c5dc 100644 --- a/packages/just-scripts/src/tasks/webpackDevServerTask.ts +++ b/packages/just-scripts/src/tasks/webpackDevServerTask.ts @@ -5,7 +5,6 @@ import { resolve, resolveCwd, TaskFunction } from 'just-task'; import * as fs from 'fs'; import * as path from 'path'; import { WebpackCliTaskOptions } from './webpackCliTask'; -import { getTsNodeEnv } from '../typescript/getTsNodeEnv'; import { findWebpackConfig } from '../webpack/findWebpackConfig'; import * as semver from 'semver'; @@ -35,16 +34,6 @@ export interface WebpackDevServerTaskOptions extends WebpackCliTaskOptions, Conf * Environment variables to be passed to the spawned process of webpack-dev-server */ env?: { [key: string]: string | undefined }; - - /** - * The tsconfig file to pass to ts-node for Typescript config - */ - tsconfig?: string; - - /** - * Transpile the config only - */ - transpileOnly?: boolean; } export function webpackDevServerTask(options: WebpackDevServerTaskOptions = {}): TaskFunction { @@ -75,10 +64,6 @@ export function webpackDevServerTask(options: WebpackDevServerTaskOptions = {}): if (configPath && fs.existsSync(configPath)) { args = [...args, '--config', configPath]; - options.env = { - ...options.env, - ...(configPath.endsWith('.ts') && getTsNodeEnv(options.tsconfig, options.transpileOnly)), - }; } if (options.open) { diff --git a/packages/just-scripts/src/tasks/webpackTask.ts b/packages/just-scripts/src/tasks/webpackTask.ts index 2bb70cba..a0692191 100644 --- a/packages/just-scripts/src/tasks/webpackTask.ts +++ b/packages/just-scripts/src/tasks/webpackTask.ts @@ -6,7 +6,6 @@ import * as fs from 'fs'; import * as path from 'path'; import { merge } from 'webpack-merge'; import { findWebpackConfig } from '../webpack/findWebpackConfig'; -import { enableTypeScript } from 'just-task/lib/enableTypeScript'; export interface WebpackTaskOptions extends Configuration { config?: string; @@ -19,11 +18,6 @@ export interface WebpackTaskOptions extends Configuration { */ env?: NodeJS.ProcessEnv; - /** - * Transpile the config only - */ - transpileOnly?: boolean; - /** * Optional callback triggered on compile */ @@ -46,11 +40,6 @@ export function webpackTask(options?: WebpackTaskOptions): TaskFunction { logger.info(`Webpack Config Path: ${webpackConfigPath}`); - if (webpackConfigPath && fs.existsSync(webpackConfigPath) && webpackConfigPath.endsWith('.ts')) { - const transpileOnly = options ? options.transpileOnly !== false : true; - enableTypeScript({ transpileOnly }); - } - const configLoader = webpackConfigPath ? require(path.resolve(webpackConfigPath)) : {}; let webpackConfigs: Configuration[]; diff --git a/packages/just-scripts/src/typescript/getTsNodeEnv.ts b/packages/just-scripts/src/typescript/getTsNodeEnv.ts deleted file mode 100644 index 4861dfa0..00000000 --- a/packages/just-scripts/src/typescript/getTsNodeEnv.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { logger } from 'just-task'; - -export function getTsNodeEnv(tsconfig?: string, transpileOnly?: boolean): { [key: string]: string | undefined } { - const env: { [key: string]: string | undefined } = {}; - - if (tsconfig) { - logger.info(`[TS] Using ${tsconfig}`); - env.TS_NODE_PROJECT = tsconfig; - } else { - const compilerOptions = JSON.stringify({ module: 'commonjs', target: 'es2017', moduleResolution: 'node' }); - logger.info(`[TS] Using these compilerOptions: ${compilerOptions}`); - env.TS_NODE_COMPILER_OPTIONS = compilerOptions; - } - - if (transpileOnly !== false) { - logger.info('[TS] Using transpileOnly mode'); - env.TS_NODE_TRANSPILE_ONLY = 'true'; - } - - return env; -} diff --git a/packages/just-task/src/__tests__/resolve.spec.ts b/packages/just-task/src/__tests__/resolve.spec.ts index 99e735f6..10d9c2e5 100644 --- a/packages/just-task/src/__tests__/resolve.spec.ts +++ b/packages/just-task/src/__tests__/resolve.spec.ts @@ -196,68 +196,73 @@ describe('resolve', () => { }); }); -describe.each(['just.config.js', 'just.config.cjs', 'just.config.ts', 'just.config.cts', 'just-task.js'])( - 'resolveConfigFile (%s)', - configPath => { - afterEach(() => { - mockfs.restore(); - resetResolvePaths(); - }); +describe.each([ + 'just.config.js', + 'just.config.cjs', + 'just.config.mjs', + 'just.config.ts', + 'just.config.cts', + 'just.config.mts', + 'just-task.js', +])('resolveConfigFile (%s)', configPath => { + afterEach(() => { + mockfs.restore(); + resetResolvePaths(); + }); - it('default chooses local config', () => { - mockfs({ - config: { - 'configArgument.ts': 'formConfig', - 'defaultConfigArgument.ts': 'formDefaultConfig', - }, - [configPath]: 'localConfig', - }); - const resolvedConfig = config.resolveConfigFile({ config: undefined, defaultConfig: undefined } as any); - expect(resolvedConfig).toContain(configPath); + it('default chooses local config', () => { + mockfs({ + config: { + 'configArgument.ts': 'formConfig', + 'defaultConfigArgument.ts': 'formDefaultConfig', + }, + [configPath]: 'localConfig', }); + const resolvedConfig = config.resolveConfigFile({ config: undefined, defaultConfig: undefined } as any); + expect(resolvedConfig).toContain(configPath); + }); - it('config argument wins over local config and defaultConfig', () => { - mockfs({ - config: { - 'configArgument.ts': 'formConfig', - 'defaultConfigArgument.ts': 'formDefaultConfig', - }, - [configPath]: 'localConfig', - }); - const resolvedConfig = config.resolveConfigFile({ - config: './config/configArgument.ts', - defaultConfig: './config/defaultConfigArgument.ts', - } as any); - expect(resolvedConfig).toContain('configArgument.ts'); + it('config argument wins over local config and defaultConfig', () => { + mockfs({ + config: { + 'configArgument.ts': 'formConfig', + 'defaultConfigArgument.ts': 'formDefaultConfig', + }, + [configPath]: 'localConfig', }); + const resolvedConfig = config.resolveConfigFile({ + config: './config/configArgument.ts', + defaultConfig: './config/defaultConfigArgument.ts', + } as any); + expect(resolvedConfig).toContain('configArgument.ts'); + }); - it('local config file wins over defaultConfig', () => { - mockfs({ - config: { - 'configArgument.ts': 'formConfig', - 'defaultConfigArgument.ts': 'formDefaultConfig', - }, - [configPath]: 'localConfig', - }); - const resolvedConfig = config.resolveConfigFile({ - config: undefined, - defaultConfig: './config/defaultConfigArgument.ts', - } as any); - expect(resolvedConfig).toContain(configPath); + it('local config file wins over defaultConfig', () => { + mockfs({ + config: { + 'configArgument.ts': 'formConfig', + 'defaultConfigArgument.ts': 'formDefaultConfig', + }, + [configPath]: 'localConfig', }); + const resolvedConfig = config.resolveConfigFile({ + config: undefined, + defaultConfig: './config/defaultConfigArgument.ts', + } as any); + expect(resolvedConfig).toContain(configPath); + }); - it('default config is used as last fallback', () => { - mockfs({ - config: { - 'configArgument.ts': 'formConfig', - 'defaultConfigArgument.ts': 'formDefaultConfig', - }, - }); - const resolvedConfig = config.resolveConfigFile({ - config: undefined, - defaultConfig: './config/defaultConfigArgument.ts', - } as any); - expect(resolvedConfig).toContain('defaultConfigArgument.ts'); + it('default config is used as last fallback', () => { + mockfs({ + config: { + 'configArgument.ts': 'formConfig', + 'defaultConfigArgument.ts': 'formDefaultConfig', + }, }); - }, -); + const resolvedConfig = config.resolveConfigFile({ + config: undefined, + defaultConfig: './config/defaultConfigArgument.ts', + } as any); + expect(resolvedConfig).toContain('defaultConfigArgument.ts'); + }); +}); diff --git a/packages/just-task/src/cli.ts b/packages/just-task/src/cli.ts index de9ad6f8..22a2f6af 100644 --- a/packages/just-task/src/cli.ts +++ b/packages/just-task/src/cli.ts @@ -47,11 +47,6 @@ option('defaultConfig', { describe: 'path to a default just configuration file that will be used when the current project does not have a just configuration file. (includes the file name, e.g. /path/to/just.config.ts)', }); -option('esm', { - describe: - 'Configure ts-node to support imports of ESM package (changes TS module/moduleResolution settings to Node16)', -}); - const registry = undertaker.registry(); const configModule = readConfig(); diff --git a/packages/just-task/src/config.ts b/packages/just-task/src/config.ts index d2e57a2e..5f70926c 100644 --- a/packages/just-task/src/config.ts +++ b/packages/just-task/src/config.ts @@ -1,10 +1,8 @@ import * as fs from 'fs'; -import * as path from 'path'; import { argv } from './option'; import { resolve } from './resolve'; import { mark, logger } from './logger'; -import { enableTypeScript } from './enableTypeScript'; import yargsParser = require('yargs-parser'); import { TaskFunction } from './interfaces'; @@ -13,9 +11,11 @@ export function resolveConfigFile(args: yargsParser.Arguments): string | null { args.config, './just.config.js', './just.config.cjs', + './just.config.mjs', './just-task.js', './just.config.ts', './just.config.cts', + './just.config.mts', args.defaultConfig, ]) { const configFile = resolve(entry); @@ -33,12 +33,6 @@ export function readConfig(): { [key: string]: TaskFunction } | void { const configFile = resolveConfigFile(args); if (configFile && fs.existsSync(configFile)) { - const ext = path.extname(configFile); - if (ext === '.cts' || ext === '.ts' || ext === '.tsx') { - // TODO: add option to do typechecking as well - enableTypeScript({ transpileOnly: true, esm: args.esm }); - } - try { const configModule = require(configFile); diff --git a/packages/just-task/src/enableTypeScript.ts b/packages/just-task/src/enableTypeScript.ts deleted file mode 100644 index f1a76da5..00000000 --- a/packages/just-task/src/enableTypeScript.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { resolve } from './resolve'; -import { logger } from './logger'; - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -export function enableTypeScript({ transpileOnly = true, esm = false }): void { - const tsNodeModule = resolve('ts-node'); - if (tsNodeModule) { - const tsNode = require(tsNodeModule); - tsNode.register({ - transpileOnly, - skipProject: true, - compilerOptions: { - target: 'es2017', - module: esm ? 'node16' : 'commonjs', - strict: false, - skipLibCheck: true, - skipDefaultLibCheck: true, - moduleResolution: esm ? 'node16' : 'node', - allowJs: true, - esModuleInterop: true, - }, - files: ['just.config.ts', 'just.config.cts'], - }); - } else { - logger.error(`In order to use TypeScript with just.config.ts, you need to install "ts-node" module: - - npm install -D ts-node - -or - - yarn add -D ts-node - -`); - } -} From f4a16926a07b56a8480f62469bf7e16a7c3093dd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 11:48:23 +0000 Subject: [PATCH 3/5] Restore parameterized JS/TS tests for nodeExecTask, remove only ts-node checks Keep describe.each over javascript/typescript with wrapCallTask helper inside the block. Remove ts-node specific checks: maybeTsAutoArgs, enableTypeScript options, TS_NODE_ env assertions, and wrapNodeExecTask. Co-authored-by: ecraig12345 <5864305+ecraig12345@users.noreply.github.com> Agent-Logs-Url: https://github.com/microsoft/just/sessions/2f3975bc-8c32-4e48-ab85-65c99e19c89d --- .../src/tasks/__tests__/nodeExecTask.test.ts | 170 +++++++++--------- yarn.lock | 138 +------------- 2 files changed, 91 insertions(+), 217 deletions(-) diff --git a/packages/just-scripts/src/tasks/__tests__/nodeExecTask.test.ts b/packages/just-scripts/src/tasks/__tests__/nodeExecTask.test.ts index ddbe506b..ac6ddcf3 100644 --- a/packages/just-scripts/src/tasks/__tests__/nodeExecTask.test.ts +++ b/packages/just-scripts/src/tasks/__tests__/nodeExecTask.test.ts @@ -32,98 +32,102 @@ describe('nodeExecTask', () => { jest.restoreAllMocks(); }); - // These tests get expensive due to the IPC, so combine the basic success cases (args, default env) - it('runs a script', async () => { - const task = nodeExecTask({ - args: ['--max-old-space-size=4096', getMockScript('mock-success.js'), '--', 'arg1', 'arg2'], - }); - await wrapCallTask(task); + describe.each(['javascript', 'typescript'])('%s', fileType => { + const ext = fileType !== 'javascript' ? 'ts' : 'js'; - expect(getNormalizedSpawnArgs(spawnSpy)).toEqual([ - '${nodeExecPath}', - '--max-old-space-size=4096', - `\${packageRoot}/src/__tests__/mock-success.js`, - '--', - 'arg1', - 'arg2', - ]); + /** Wrap a test that should be successful with extra logging in case it fails */ + async function wrapCallTask(task: TaskFunction, options?: { expectError?: boolean }) { + try { + await callTaskForTest(task); + } catch (error) { + if (options?.expectError) { + throw error; + } + // Child process failures are really hard to debug without this extra info + // (it could be because something went wrong with passing options/env) + fail( + [ + `Unexpected task failure: ${error}`, + `options: ${JSON.stringify(spawnSpy.mock.calls[0]?.[2], null, 2)}`, + 'stdout:', + stdout.getOutput(), + 'stderr:', + stderr.getOutput(), + ].join('\n'), + ); + } + if (options?.expectError) { + fail('should have thrown'); + } + } - const output = stdout.getOutput(); - expect(output).toContain('hello -- arg1 arg2\n'); - // Full process.env should be passed through to the script by default. - // Just verify one value we expect to be present. - expect(process.env.JEST_WORKER_ID).toBeTruthy(); - expect(output).toContain(`JEST_WORKER_ID=${process.env.JEST_WORKER_ID}`); - }); + // These tests get expensive due to the IPC, so combine the basic success cases (args, default env) + it('runs a script', async () => { + const task = nodeExecTask({ + args: ['--max-old-space-size=4096', getMockScript(`mock-success.${ext}`), '--', 'arg1', 'arg2'], + }); + await wrapCallTask(task); + + expect(getNormalizedSpawnArgs(spawnSpy)).toEqual([ + '${nodeExecPath}', + '--max-old-space-size=4096', + `\${packageRoot}/src/__tests__/mock-success.${ext}`, + '--', + 'arg1', + 'arg2', + ]); - it('handles a script that fails', async () => { - const task = nodeExecTask({ - args: [getMockScript('mock-fail.js')], + const output = stdout.getOutput(); + expect(output).toContain('hello -- arg1 arg2\n'); + // Full process.env should be passed through to the script by default. + // Just verify one value we expect to be present. + expect(process.env.JEST_WORKER_ID).toBeTruthy(); + expect(output).toContain(`JEST_WORKER_ID=${process.env.JEST_WORKER_ID}`); }); - try { - await wrapCallTask(task, { expectError: true }); - } catch (error) { - expect((error as Error).message).toContain('Command failed'); - expect((error as any).code).toBe(1); - // in the debugger there are some extra stderr chunks - expect(stderr.getOutput()).toContain('oh no\n'); - } - }); - it('passes specified env only', async () => { - const task = nodeExecTask({ - args: [getMockScript('mock-success.js')], - env: { FOO: 'foo value', BAR: 'bar value' }, + it('handles a script that fails', async () => { + const task = nodeExecTask({ + args: [getMockScript(`mock-fail.${ext}`)], + }); + try { + await wrapCallTask(task, { expectError: true }); + } catch (error) { + expect((error as Error).message).toContain('Command failed'); + expect((error as any).code).toBe(1); + // in the debugger there are some extra stderr chunks + expect(stderr.getOutput()).toContain('oh no\n'); + } }); - await wrapCallTask(task); - const output = stdout.getOutput(); - // can't strictly check due to OS-injected values - expect(output).toContain('FOO=foo value'); - expect(output).toContain('BAR=bar value'); - // verify a value we expect to be present in the current process isn't passed through - expect(process.env.JEST_WORKER_ID).toBeTruthy(); - expect(output).not.toContain('JEST_WORKER_ID'); - }); + it('passes specified env only', async () => { + const task = nodeExecTask({ + args: [getMockScript(`mock-success.${ext}`)], + env: { FOO: 'foo value', BAR: 'bar value' }, + }); + await wrapCallTask(task); - it('errors if file not found', async () => { - const script = path.join(__dirname, 'nope.js'); - const task = nodeExecTask({ - args: [script], + const output = stdout.getOutput(); + // can't strictly check due to OS-injected values + expect(output).toContain('FOO=foo value'); + expect(output).toContain('BAR=bar value'); + // verify a value we expect to be present in the current process isn't passed through + expect(process.env.JEST_WORKER_ID).toBeTruthy(); + expect(output).not.toContain('JEST_WORKER_ID'); }); - try { - await wrapCallTask(task, { expectError: true }); - } catch (error) { - expect((error as Error).message).toContain('Command failed'); - expect((error as any).code).toBe(1); - const output = stderr.getOutput(); - expect(output).toContain('Error: Cannot find module'); - } - }); - /** Wrap a test that should be successful with extra logging in case it fails */ - async function wrapCallTask(task: TaskFunction, options?: { expectError?: boolean }) { - try { - await callTaskForTest(task); - } catch (error) { - if (options?.expectError) { - throw error; + it('errors if file not found', async () => { + const script = path.join(__dirname, `nope.${ext}`); + const task = nodeExecTask({ + args: [script], + }); + try { + await wrapCallTask(task, { expectError: true }); + } catch (error) { + expect((error as Error).message).toContain('Command failed'); + expect((error as any).code).toBe(1); + const output = stderr.getOutput(); + expect(output).toContain('Error: Cannot find module'); } - // Child process failures are really hard to debug without this extra info - // (it could be because something went wrong with passing options/env) - fail( - [ - `Unexpected task failure: ${error}`, - `options: ${JSON.stringify(spawnSpy.mock.calls[0]?.[2], null, 2)}`, - 'stdout:', - stdout.getOutput(), - 'stderr:', - stderr.getOutput(), - ].join('\n'), - ); - } - if (options?.expectError) { - fail('should have thrown'); - } - } + }); + }); }); diff --git a/yarn.lock b/yarn.lock index d04b808d..ed1e97c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -381,15 +381,6 @@ __metadata: languageName: node linkType: hard -"@cspotcode/source-map-support@npm:^0.8.0": - version: 0.8.1 - resolution: "@cspotcode/source-map-support@npm:0.8.1" - dependencies: - "@jridgewell/trace-mapping": "npm:0.3.9" - checksum: 10c0/05c5368c13b662ee4c122c7bfbe5dc0b613416672a829f3e78bc49a357a197e0218d6e74e7c66cfcd04e15a179acab080bd3c69658c9fbefd0e1ccd950a07fc6 - languageName: node - linkType: hard - "@emnapi/core@npm:^1.4.3": version: 1.9.1 resolution: "@emnapi/core@npm:1.9.1" @@ -819,30 +810,20 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": +"@jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.2 resolution: "@jridgewell/resolve-uri@npm:3.1.2" checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": +"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": version: 1.5.5 resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:0.3.9": - version: 0.3.9 - resolution: "@jridgewell/trace-mapping@npm:0.3.9" - dependencies: - "@jridgewell/resolve-uri": "npm:^3.0.3" - "@jridgewell/sourcemap-codec": "npm:^1.4.10" - checksum: 10c0/fa425b606d7c7ee5bfa6a31a7b050dd5814b4082f318e0e4190f991902181b4330f43f4805db1dd4f2433fd0ed9cc7a7b9c2683f1deeab1df1b0a98b1e24055b - languageName: node - linkType: hard - "@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.23, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25, @jridgewell/trace-mapping@npm:^0.3.28": version: 0.3.31 resolution: "@jridgewell/trace-mapping@npm:0.3.31" @@ -1117,34 +1098,6 @@ __metadata: languageName: node linkType: hard -"@tsconfig/node10@npm:^1.0.7": - version: 1.0.12 - resolution: "@tsconfig/node10@npm:1.0.12" - checksum: 10c0/7bbbd7408cfaced86387a9b1b71cebc91c6fd701a120369735734da8eab1a4773fc079abd9f40c9e0b049e12586c8ac0e13f0da596bfd455b9b4c3faa813ebc5 - languageName: node - linkType: hard - -"@tsconfig/node12@npm:^1.0.7": - version: 1.0.11 - resolution: "@tsconfig/node12@npm:1.0.11" - checksum: 10c0/dddca2b553e2bee1308a056705103fc8304e42bb2d2cbd797b84403a223b25c78f2c683ec3e24a095e82cd435387c877239bffcb15a590ba817cd3f6b9a99fd9 - languageName: node - linkType: hard - -"@tsconfig/node14@npm:^1.0.0": - version: 1.0.3 - resolution: "@tsconfig/node14@npm:1.0.3" - checksum: 10c0/67c1316d065fdaa32525bc9449ff82c197c4c19092b9663b23213c8cbbf8d88b6ed6a17898e0cbc2711950fbfaf40388938c1c748a2ee89f7234fc9e7fe2bf44 - languageName: node - linkType: hard - -"@tsconfig/node16@npm:^1.0.2": - version: 1.0.4 - resolution: "@tsconfig/node16@npm:1.0.4" - checksum: 10c0/05f8f2734e266fb1839eb1d57290df1664fe2aa3b0fdd685a9035806daa635f7519bf6d5d9b33f6e69dd545b8c46bd6e2b5c79acb2b1f146e885f7f11a42a5bb - languageName: node - linkType: hard - "@tybys/wasm-util@npm:^0.10.0": version: 0.10.1 resolution: "@tybys/wasm-util@npm:0.10.1" @@ -1750,16 +1703,7 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.1.1": - version: 8.3.5 - resolution: "acorn-walk@npm:8.3.5" - dependencies: - acorn: "npm:^8.11.0" - checksum: 10c0/e31bf5b5423ed1349437029d66d708b9fbd1b77a644b031501e2c753b028d13b56348210ed901d5b1d0d86eb3381c0a0fc0d0998511a9d546d1194936266a332 - languageName: node - linkType: hard - -"acorn@npm:^8.11.0, acorn@npm:^8.4.1, acorn@npm:^8.9.0": +"acorn@npm:^8.9.0": version: 8.16.0 resolution: "acorn@npm:8.16.0" bin: @@ -1881,13 +1825,6 @@ __metadata: languageName: node linkType: hard -"arg@npm:^4.1.0": - version: 4.1.3 - resolution: "arg@npm:4.1.3" - checksum: 10c0/070ff801a9d236a6caa647507bdcc7034530604844d64408149a26b9e87c2f97650055c0f049abd1efc024b334635c01f29e0b632b371ac3f26130f4cf65997a - languageName: node - linkType: hard - "argparse@npm:^1.0.7, argparse@npm:~1.0.9": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -2343,13 +2280,6 @@ __metadata: languageName: node linkType: hard -"create-require@npm:^1.1.0": - version: 1.1.1 - resolution: "create-require@npm:1.1.1" - checksum: 10c0/157cbc59b2430ae9a90034a5f3a1b398b6738bf510f713edc4d4e45e169bc514d3d99dd34d8d01ca7ae7830b5b8b537e46ae8f3c8f932371b0875c0151d7ec91 - languageName: node - linkType: hard - "cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" @@ -2413,13 +2343,6 @@ __metadata: languageName: node linkType: hard -"diff@npm:^4.0.1": - version: 4.0.4 - resolution: "diff@npm:4.0.4" - checksum: 10c0/855fb70b093d1d9643ddc12ea76dca90dc9d9cdd7f82c08ee8b9325c0dc5748faf3c82e2047ced5dcaa8b26e58f7903900be2628d0380a222c02d79d8de385df - languageName: node - linkType: hard - "diff@npm:~8.0.2": version: 8.0.4 resolution: "diff@npm:8.0.4" @@ -4008,7 +3931,6 @@ __metadata: resolution: "just-example-lib@workspace:packages/just-example-lib" dependencies: just-scripts: "workspace:^" - ts-node: "npm:^10.8.0" languageName: unknown linkType: soft @@ -4220,7 +4142,7 @@ __metadata: languageName: node linkType: hard -"make-error@npm:^1.1.1, make-error@npm:^1.3.6": +"make-error@npm:^1.3.6": version: 1.3.6 resolution: "make-error@npm:1.3.6" checksum: 10c0/171e458d86854c6b3fc46610cfacf0b45149ba043782558c6875d9f42f222124384ad0b468c92e996d815a8a2003817a710c0a160e49c1c394626f76fa45396f @@ -5429,44 +5351,6 @@ __metadata: languageName: node linkType: hard -"ts-node@npm:^10.8.0": - version: 10.9.2 - resolution: "ts-node@npm:10.9.2" - dependencies: - "@cspotcode/source-map-support": "npm:^0.8.0" - "@tsconfig/node10": "npm:^1.0.7" - "@tsconfig/node12": "npm:^1.0.7" - "@tsconfig/node14": "npm:^1.0.0" - "@tsconfig/node16": "npm:^1.0.2" - acorn: "npm:^8.4.1" - acorn-walk: "npm:^8.1.1" - arg: "npm:^4.1.0" - create-require: "npm:^1.1.0" - diff: "npm:^4.0.1" - make-error: "npm:^1.1.1" - v8-compile-cache-lib: "npm:^3.0.1" - yn: "npm:3.1.1" - peerDependencies: - "@swc/core": ">=1.2.50" - "@swc/wasm": ">=1.2.50" - "@types/node": "*" - typescript: ">=2.7" - peerDependenciesMeta: - "@swc/core": - optional: true - "@swc/wasm": - optional: true - bin: - ts-node: dist/bin.js - ts-node-cwd: dist/bin-cwd.js - ts-node-esm: dist/bin-esm.js - ts-node-script: dist/bin-script.js - ts-node-transpile-only: dist/bin-transpile.js - ts-script: dist/bin-script-deprecated.js - checksum: 10c0/5f29938489f96982a25ba650b64218e83a3357d76f7bede80195c65ab44ad279c8357264639b7abdd5d7e75fc269a83daa0e9c62fd8637a3def67254ecc9ddc2 - languageName: node - linkType: hard - "tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" @@ -5701,13 +5585,6 @@ __metadata: languageName: node linkType: hard -"v8-compile-cache-lib@npm:^3.0.1": - version: 3.0.1 - resolution: "v8-compile-cache-lib@npm:3.0.1" - checksum: 10c0/bdc36fb8095d3b41df197f5fb6f11e3a26adf4059df3213e3baa93810d8f0cc76f9a74aaefc18b73e91fe7e19154ed6f134eda6fded2e0f1c8d2272ed2d2d391 - languageName: node - linkType: hard - "v8-to-istanbul@npm:^9.0.1": version: 9.3.0 resolution: "v8-to-istanbul@npm:9.3.0" @@ -5893,13 +5770,6 @@ __metadata: languageName: node linkType: hard -"yn@npm:3.1.1": - version: 3.1.1 - resolution: "yn@npm:3.1.1" - checksum: 10c0/0732468dd7622ed8a274f640f191f3eaf1f39d5349a1b72836df484998d7d9807fbea094e2f5486d6b0cd2414aad5775972df0e68f8604db89a239f0f4bf7443 - languageName: node - linkType: hard - "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" From c7c787d58a27743fe1085e5ba5b94e475a3a3423 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 12:21:08 +0000 Subject: [PATCH 4/5] Add major beachball change files for just-task and just-scripts Co-authored-by: ecraig12345 <5864305+ecraig12345@users.noreply.github.com> Agent-Logs-Url: https://github.com/microsoft/just/sessions/9c03c317-190f-4365-8e96-0c7aa67397d3 --- .../change-04d54498-920f-49a4-b451-0fa517df8b1e.json | 11 +++++++++++ .../change-e41106ce-210a-4d8c-b5c5-cf9aaacb7105.json | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 change/change-04d54498-920f-49a4-b451-0fa517df8b1e.json create mode 100644 change/change-e41106ce-210a-4d8c-b5c5-cf9aaacb7105.json diff --git a/change/change-04d54498-920f-49a4-b451-0fa517df8b1e.json b/change/change-04d54498-920f-49a4-b451-0fa517df8b1e.json new file mode 100644 index 00000000..645344d8 --- /dev/null +++ b/change/change-04d54498-920f-49a4-b451-0fa517df8b1e.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "type": "major", + "comment": "Remove enableTypeScript, tsconfig, and transpileOnly options from nodeExecTask and webpack tasks; remove getTsNodeEnv helper", + "packageName": "just-scripts", + "email": "email not defined", + "dependentChangeType": "patch" + } + ] +} diff --git a/change/change-e41106ce-210a-4d8c-b5c5-cf9aaacb7105.json b/change/change-e41106ce-210a-4d8c-b5c5-cf9aaacb7105.json new file mode 100644 index 00000000..337d399c --- /dev/null +++ b/change/change-e41106ce-210a-4d8c-b5c5-cf9aaacb7105.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "type": "major", + "comment": "Remove ts-node support and --esm CLI option; require Node.js 22.18+ native TypeScript type-stripping", + "packageName": "just-task", + "email": "email not defined", + "dependentChangeType": "patch" + } + ] +} From 702b53e5f2f16bce7f862a555cb6df8855c14723 Mon Sep 17 00:00:00 2001 From: Elizabeth Craig Date: Thu, 26 Mar 2026 05:29:32 -0700 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Elizabeth Craig --- change/change-04d54498-920f-49a4-b451-0fa517df8b1e.json | 2 +- change/change-e41106ce-210a-4d8c-b5c5-cf9aaacb7105.json | 2 +- docs/tasks/index.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/change/change-04d54498-920f-49a4-b451-0fa517df8b1e.json b/change/change-04d54498-920f-49a4-b451-0fa517df8b1e.json index 645344d8..351722fc 100644 --- a/change/change-04d54498-920f-49a4-b451-0fa517df8b1e.json +++ b/change/change-04d54498-920f-49a4-b451-0fa517df8b1e.json @@ -2,7 +2,7 @@ "changes": [ { "type": "major", - "comment": "Remove enableTypeScript, tsconfig, and transpileOnly options from nodeExecTask and webpack tasks; remove getTsNodeEnv helper", + "comment": "Remove `enableTypeScript`, `tsconfig`, and `transpileOnly` options from `nodeExecTask` and `webpack*` tasks; remove `getTsNodeEnv` helper", "packageName": "just-scripts", "email": "email not defined", "dependentChangeType": "patch" diff --git a/change/change-e41106ce-210a-4d8c-b5c5-cf9aaacb7105.json b/change/change-e41106ce-210a-4d8c-b5c5-cf9aaacb7105.json index 337d399c..275c4e10 100644 --- a/change/change-e41106ce-210a-4d8c-b5c5-cf9aaacb7105.json +++ b/change/change-e41106ce-210a-4d8c-b5c5-cf9aaacb7105.json @@ -2,7 +2,7 @@ "changes": [ { "type": "major", - "comment": "Remove ts-node support and --esm CLI option; require Node.js 22.18+ native TypeScript type-stripping", + "comment": "Remove `ts-node` support and `--esm` CLI option; require Node.js 22.18+ native TypeScript type-stripping", "packageName": "just-task", "email": "email not defined", "dependentChangeType": "patch" diff --git a/docs/tasks/index.md b/docs/tasks/index.md index 90f8a622..962f3cdb 100644 --- a/docs/tasks/index.md +++ b/docs/tasks/index.md @@ -23,7 +23,7 @@ task('sayhello', function () { ## Defining tasks in style with TypeScript -Node.js 22.18+ supports running TypeScript natively via [type stripping](https://nodejs.org/docs/latest-v22.x/api/typescript.html#type-stripping). Just takes advantage of this, so you only need `typescript` installed: +Node.js 22.18+ supports running TypeScript natively via [type stripping](https://nodejs.org/docs/latest-v22.x/api/typescript.html#type-stripping). Just takes advantage of this, so you only need `typescript` installed to make things work in your IDE: ``` npm i -D typescript