diff --git a/packages/create-app/src/app.ts b/packages/create-app/src/app.ts index a88cd6c..b4b105b 100644 --- a/packages/create-app/src/app.ts +++ b/packages/create-app/src/app.ts @@ -1,9 +1,10 @@ // Copyright 2024 Bloomberg Finance L.P. // Distributed under the terms of the Apache 2.0 license. -import { buildApplication, buildCommand } from "@stricli/core"; +import { buildApplication, buildCommand, numberParser } from "@stricli/core"; import packageJson from "../package.json"; const command = buildCommand({ + /* c8 ignore next */ loader: async () => import("./impl"), parameters: { positional: { @@ -66,6 +67,13 @@ const command = buildCommand({ parse: String, default: "", }, + nodeVersion: { + kind: "parsed", + brief: "Node.js major version to use for engines.node minimum and @types/node, bypasses version discovery logic", + parse: numberParser, + optional: true, + hidden: true, + }, }, aliases: { n: "name", diff --git a/packages/create-app/src/impl.ts b/packages/create-app/src/impl.ts index 2ebb9e9..3629156 100644 --- a/packages/create-app/src/impl.ts +++ b/packages/create-app/src/impl.ts @@ -2,6 +2,7 @@ // Distributed under the terms of the Apache 2.0 license. import type { PackageJson, TsConfigJson } from "type-fest"; import self from "../package.json"; +import type { LocalContext } from "./context"; import { binBashCompleteModuleText, binBashCompleteScriptText, @@ -19,8 +20,8 @@ import { singleCommandAppText, singleCommandImplText, } from "./files"; +import { calculateAcceptableNodeVersions, type NodeVersions } from "./node"; import srcTsconfig from "./tsconfig.json"; -import type { LocalContext } from "./context"; interface TsupConfig { entry?: string[]; @@ -45,7 +46,7 @@ type PackageJsonTemplateValues = Pick & function buildPackageJson( values: PackageJsonTemplateValues, commandName: string, - nodeMajorVersion: number, + nodeVersions: NodeVersions, ): LocalPackageJson { return { ...values, @@ -55,7 +56,7 @@ function buildPackageJson( [commandName]: "dist/cli.js", }, engines: { - node: `>=${nodeMajorVersion}`, + node: nodeVersions.engine, }, scripts: { prebuild: "tsc -p src/tsconfig.json", @@ -74,7 +75,7 @@ function buildPackageJson( "@stricli/core": self.dependencies["@stricli/core"], }, devDependencies: { - "@types/node": `${nodeMajorVersion}.x`, + "@types/node": nodeVersions.types, tsup: self.devDependencies.tsup, typescript: self.devDependencies.typescript, }, @@ -114,6 +115,7 @@ export interface CreateProjectFlags extends PackageJsonTemplateValues { readonly template: "single" | "multi"; readonly autoComplete: boolean; readonly command?: string; + readonly nodeVersion?: number; } export default async function (this: LocalContext, flags: CreateProjectFlags, directoryPath: string): Promise { @@ -135,8 +137,13 @@ export default async function (this: LocalContext, flags: CreateProjectFlags, di const packageName = flags.name ?? path.basename(directoryPath); const commandName = flags.command ?? packageName; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const nodeMajorVersion = this.process.versions.node.split(".").map(Number)[0]!; + + let nodeVersions: NodeVersions; + if (flags.nodeVersion) { + nodeVersions = { engine: `>=${flags.nodeVersion}`, types: `${flags.nodeVersion}.x` }; + } else { + nodeVersions = await calculateAcceptableNodeVersions(this.process); + } let packageJson = buildPackageJson( { @@ -147,7 +154,7 @@ export default async function (this: LocalContext, flags: CreateProjectFlags, di type: flags.type, }, commandName, - nodeMajorVersion, + nodeVersions, ); const bashCommandName = calculateBashCompletionCommand(commandName); diff --git a/packages/create-app/src/node.ts b/packages/create-app/src/node.ts new file mode 100644 index 0000000..8b55bbf --- /dev/null +++ b/packages/create-app/src/node.ts @@ -0,0 +1,64 @@ +// Copyright 2024 Bloomberg Finance L.P. +// Distributed under the terms of the Apache 2.0 license. +import { discoverPackageRegistry, fetchPackageVersions } from "./registry"; + +export interface NodeVersions { + readonly engine: string; + readonly types: string; +} + +const MAXIMUM_KNOWN_SAFE_NODE_TYPES_VERSION = 22; + +export async function calculateAcceptableNodeVersions(process: NodeJS.Process): Promise { + const majorVersion = Number(process.versions.node.split(".")[0]); + let typesVersion: string | undefined; + + if (majorVersion > MAXIMUM_KNOWN_SAFE_NODE_TYPES_VERSION) { + // To avoid hitting the registry every time, only run when higher than a statically-known maximum safe value. + const registry = discoverPackageRegistry(process); + const versions = registry && (await fetchPackageVersions(registry, "@types/node")); + if (versions?.includes(process.versions.node)) { + typesVersion = `^${process.versions.node}`; + } else if (versions) { + const typeMajors = new Set(versions.map((version) => Number(version.split(".")[0]))); + if (typeMajors.has(majorVersion)) { + // Previously unknown major version exists, which means MAXIMUM_KNOWN_SAFE_NODE_TYPES_VERSION should be updated. + typesVersion = `${majorVersion}.x`; + } else { + // Filter available major versions to just even (LTS) and pick highest. + // This assumes that types will exist for the LTS version just prior to the current unknown major version. + const highestEvenTypeMajor = [...typeMajors] + .filter((major) => major % 2 === 0) + .toSorted() + .at(-1); + if (highestEvenTypeMajor) { + typesVersion = `${highestEvenTypeMajor}.x`; + process.stderr.write( + `No version of @types/node found with major ${majorVersion}, falling back to ${typesVersion}\n`, + ); + process.stderr.write( + `Rerun this command with the hidden flag --node-version to manually specify the Node.js major version`, + ); + } + } + } + } else { + typesVersion = `${majorVersion}.x`; + } + + if (!typesVersion) { + typesVersion = `${majorVersion}.x`; + // Should only be hit if something went wrong determining registry URL or fetching from registry. + process.stderr.write( + `Unable to determine version of @types/node for ${process.versions.node}, assuming ${typesVersion}\n`, + ); + process.stderr.write( + `Rerun this command with the hidden flag --node-version to manually specify the Node.js major version`, + ); + } + + return { + engine: `>=${majorVersion}`, + types: typesVersion, + }; +} diff --git a/packages/create-app/src/registry.ts b/packages/create-app/src/registry.ts new file mode 100644 index 0000000..e42358e --- /dev/null +++ b/packages/create-app/src/registry.ts @@ -0,0 +1,29 @@ +// Copyright 2024 Bloomberg Finance L.P. +// Distributed under the terms of the Apache 2.0 license. +import child_process from "node:child_process"; + +export function discoverPackageRegistry(process: NodeJS.Process): string | undefined { + if (process.env["NPM_CONFIG_REGISTRY"]) { + return process.env["NPM_CONFIG_REGISTRY"]; + } + + if (process.env["NPM_EXECPATH"]) { + return child_process + .execFileSync(process.execPath, [process.env["NPM_EXECPATH"], "config", "get", "registry"], { + encoding: "utf-8", + }) + .trim(); + } +} + +export async function fetchPackageVersions( + registry: string, + packageName: string, +): Promise { + const input = registry + (registry.endsWith("/") ? packageName : `/${packageName}`); + const response = await fetch(input); + const data = await response.json(); + if (typeof data === "object" && data && "versions" in data && typeof data.versions === "object") { + return Object.keys(data.versions ?? {}); + } +} diff --git a/packages/create-app/tests/app.spec.ts b/packages/create-app/tests/app.spec.ts index 00126ad..704b11b 100644 --- a/packages/create-app/tests/app.spec.ts +++ b/packages/create-app/tests/app.spec.ts @@ -2,8 +2,10 @@ // Distributed under the terms of the Apache 2.0 license. import { run } from "@stricli/core"; import { expect } from "chai"; +import child_process from "child_process"; import { createFsFromVolume, Volume, type DirectoryJSON } from "memfs"; import nodePath from "node:path"; +import url from "node:url"; import sinon from "sinon"; import type { PackageJson } from "type-fest"; import { app } from "../src/app"; @@ -22,6 +24,33 @@ interface ApplicationTestResult { readonly files: DirectoryJSON; } +const repoRootUrl = new url.URL("..", import.meta.url); +const repoRootPath = url.fileURLToPath(repoRootUrl); +const repoRootRegex = new RegExp(repoRootPath.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"), "ig"); + +const REPO_ROOT_REPLACEMENT = "#/"; + +function sanitizeStackTraceReferences(text: string): string { + return text + .split("\n") + .filter((line) => { + if (line.startsWith(" at ") && (line.includes("node_modules") || line.includes("node:"))) { + return false; + } + return true; + }) + .map((line) => { + if (line.startsWith(" at ")) { + line = line.replaceAll(repoRootUrl.href, REPO_ROOT_REPLACEMENT); + line = line.replaceAll(repoRootRegex, REPO_ROOT_REPLACEMENT); + line = line.replaceAll(nodePath.win32.sep, nodePath.posix.sep); + line = line.replaceAll(/:\d+/g, ":?"); + } + return line; + }) + .join("\n"); +} + const FILE_ENTRY_PREFIX = "::::"; const ApplicationTestResultFormat: BaselineFormat = { @@ -45,8 +74,8 @@ const ApplicationTestResultFormat: BaselineFormat = { const stdoutStartIdx = lines.indexOf("[STDOUT]"); const stderrStartIdx = lines.indexOf("[STDERR]"); const filesStartIdx = lines.indexOf("[FILES]"); - const stdout = lines.slice(stdoutStartIdx + 1, stderrStartIdx - 1).join("\n"); - const stderr = lines.slice(stderrStartIdx + 1, filesStartIdx - 1).join("\n"); + const stdout = lines.slice(stdoutStartIdx + 1, stderrStartIdx).join("\n"); + const stderr = lines.slice(stderrStartIdx + 1, filesStartIdx).join("\n"); const filesText = lines.slice(filesStartIdx).join("\n").split(FILE_ENTRY_PREFIX).slice(1); const vol = Volume.fromJSON({}); for (const fileText of filesText) { @@ -66,7 +95,7 @@ const ApplicationTestResultFormat: BaselineFormat = { yield "[STDOUT]"; yield result.stdout; yield "[STDERR]"; - yield result.stderr; + yield sanitizeStackTraceReferences(result.stderr); yield "[FILES]"; const fileEntries = Object.entries(result.files).sort((a, b) => a[0].localeCompare(b[0])); for (const [path, text] of fileEntries) { @@ -387,4 +416,561 @@ describe("creates new application", () => { }); }); }); + + describe("checks for @types__node", () => { + const currentNodeMajorVersion = Number(process.versions.node.split(".")[0]); + const futureLTSNodeMajorVersion = currentNodeMajorVersion + (currentNodeMajorVersion % 2 === 0 ? 10 : 11); + + let sandbox: sinon.SinonSandbox; + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + afterEach(() => { + sandbox.restore(); + }); + + describe("registry logic", () => { + it("unable to discover registry from process", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + versions: { + node: `${futureLTSNodeMajorVersion}.0.0`, + }, + env: {}, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + }); + + it("no check for safe major version", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const execFileSync = sandbox.stub(child_process, "execFileSync"); + execFileSync.returns("REGISTRY"); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.resolves(new Response(JSON.stringify({}))); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + versions: { + node: `${currentNodeMajorVersion}.0.0`, + }, + env: { + NPM_CONFIG_REGISTRY: "NPM_CONFIG_REGISTRY", + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(execFileSync.callCount).to.equal(0, "execFileSync called unexpectedly"); + expect(fetch.callCount).to.equal(0, "fetch called unexpectedly"); + }); + + it("reads registry direct from NPM_CONFIG_REGISTRY", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const execFileSync = sandbox.stub(child_process, "execFileSync"); + execFileSync.returns("REGISTRY"); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.resolves(new Response(JSON.stringify({}))); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + versions: { + node: `${futureLTSNodeMajorVersion}.0.0`, + }, + env: { + NPM_CONFIG_REGISTRY: "NPM_CONFIG_REGISTRY", + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(execFileSync.callCount).to.equal(0, "execFileSync called unexpectedly"); + expect(fetch.callCount).to.equal(1, "fetch called an unexpected number of times"); + expect(fetch.args[0]?.[0]).to.equal( + "NPM_CONFIG_REGISTRY/@types/node", + "fetch called with unexpected argument", + ); + }); + + it("reads registry direct from NPM_CONFIG_REGISTRY, URL ends with slash", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const execFileSync = sandbox.stub(child_process, "execFileSync"); + execFileSync.returns("REGISTRY"); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.resolves(new Response(JSON.stringify({}))); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + versions: { + node: `${futureLTSNodeMajorVersion}.0.0`, + }, + env: { + NPM_CONFIG_REGISTRY: "NPM_CONFIG_REGISTRY/", + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(execFileSync.callCount).to.equal(0, "execFileSync called unexpectedly"); + expect(fetch.callCount).to.equal(1, "fetch called an unexpected number of times"); + expect(fetch.args[0]?.[0]).to.equal( + "NPM_CONFIG_REGISTRY/@types/node", + "fetch called with unexpected argument", + ); + }); + + it("registry data has no versions", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const execFileSync = sandbox.stub(child_process, "execFileSync"); + execFileSync.returns("REGISTRY"); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.resolves( + new Response( + JSON.stringify({ + versions: null, + }), + ), + ); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + versions: { + node: `${futureLTSNodeMajorVersion}.0.0`, + }, + env: { + NPM_CONFIG_REGISTRY: "NPM_CONFIG_REGISTRY", + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(execFileSync.callCount).to.equal(0, "execFileSync called unexpectedly"); + expect(fetch.callCount).to.equal(1, "fetch called an unexpected number of times"); + expect(fetch.args[0]?.[0]).to.equal( + "NPM_CONFIG_REGISTRY/@types/node", + "fetch called with unexpected argument", + ); + }); + + it("request to registry throws error", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const execFileSync = sandbox.stub(child_process, "execFileSync"); + execFileSync.returns("REGISTRY"); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.rejects(new Error("Failed to fetch data from REGISTRY")); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + versions: { + node: `${futureLTSNodeMajorVersion}.0.0`, + }, + env: { + NPM_CONFIG_REGISTRY: "NPM_CONFIG_REGISTRY", + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(execFileSync.callCount).to.equal(0, "execFileSync called unexpectedly"); + expect(fetch.callCount).to.equal(1, "fetch called an unexpected number of times"); + expect(fetch.args[0]?.[0]).to.equal( + "NPM_CONFIG_REGISTRY/@types/node", + "fetch called with unexpected argument", + ); + }); + + it("uses NPM_EXECPATH to get registry config value", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const execFileSync = sandbox.stub(child_process, "execFileSync"); + execFileSync.returns("REGISTRY"); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.resolves(new Response(JSON.stringify({}))); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + execPath: "process.execPath", + versions: { + node: `${futureLTSNodeMajorVersion}.0.0`, + }, + env: { + NPM_EXECPATH: "NPM_EXECPATH", + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(execFileSync.callCount).to.equal(1, "execFileSync called an unexpected number of times"); + expect(execFileSync.args[0]).to.deep.equal( + ["process.execPath", ["NPM_EXECPATH", "config", "get", "registry"], { encoding: "utf-8" }], + "fetch called with unexpected argument", + ); + expect(fetch.callCount).to.equal(1, "fetch called an unexpected number of times"); + expect(fetch.args[0]?.[0]).to.equal("REGISTRY/@types/node", "fetch called with unexpected argument"); + }); + + it("NPM_EXECPATH throws an error", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const execFileSync = sandbox.stub(child_process, "execFileSync"); + execFileSync.throws(new Error("Failed to execute NPM_EXECPATH")); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.resolves(new Response(JSON.stringify({}))); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + execPath: "process.execPath", + versions: { + node: `${futureLTSNodeMajorVersion}.0.0`, + }, + env: { + NPM_EXECPATH: "NPM_EXECPATH", + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(execFileSync.callCount).to.equal(1, "execFileSync called an unexpected number of times"); + expect(execFileSync.args[0]).to.deep.equal( + ["process.execPath", ["NPM_EXECPATH", "config", "get", "registry"], { encoding: "utf-8" }], + "fetch called with unexpected argument", + ); + expect(fetch.callCount).to.equal(0, "fetch called unexpectedly"); + }); + }); + + describe("node version logic", () => { + it("version discovery skipped when --node-version is provided", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const execFileSync = sandbox.stub(child_process, "execFileSync"); + execFileSync.returns("REGISTRY"); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.resolves(new Response(JSON.stringify({}))); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + versions: { + node: `${futureLTSNodeMajorVersion}.0.0`, + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run( + app, + ["node-version-test", "--node-version", `${futureLTSNodeMajorVersion + 1}`], + context as LocalContext, + ); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(execFileSync.callCount).to.equal(0, "execFileSync called unexpectedly"); + expect(fetch.callCount).to.equal(0, "fetch called unexpectedly"); + }); + + it("exact version exists for types", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.resolves( + new Response( + JSON.stringify({ + versions: { + [`${futureLTSNodeMajorVersion}.0.0`]: {}, + }, + }), + ), + ); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + versions: { + node: `${futureLTSNodeMajorVersion}.0.0`, + }, + env: { + NPM_CONFIG_REGISTRY: "NPM_CONFIG_REGISTRY", + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(fetch.callCount).to.equal(1, "fetch called an unexpected number of times"); + expect(fetch.args[0]?.[0]).to.equal( + "NPM_CONFIG_REGISTRY/@types/node", + "fetch called with unexpected argument", + ); + }); + + it("major version exists in registry", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.resolves( + new Response( + JSON.stringify({ + versions: { + [`${futureLTSNodeMajorVersion}.0.0`]: {}, + }, + }), + ), + ); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + versions: { + node: `${futureLTSNodeMajorVersion}.1.1`, + }, + env: { + NPM_CONFIG_REGISTRY: "NPM_CONFIG_REGISTRY", + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(fetch.callCount).to.equal(1, "fetch called an unexpected number of times"); + expect(fetch.args[0]?.[0]).to.equal( + "NPM_CONFIG_REGISTRY/@types/node", + "fetch called with unexpected argument", + ); + }); + + it("major version does not exist in registry, picks highest even major", async function () { + const stdout = new FakeWritableStream(); + const stderr = new FakeWritableStream(); + const cwd = sinon.stub().returns("/home"); + const vol = Volume.fromJSON({}); + const memfs = createFsFromVolume(vol); + + const fetch = sandbox.stub(globalThis, "fetch"); + fetch.resolves( + new Response( + JSON.stringify({ + versions: { + [`${currentNodeMajorVersion}.0.0`]: {}, + }, + }), + ), + ); + + const context: DeepPartial = { + process: { + stdout, + stderr, + cwd, + versions: { + node: `${futureLTSNodeMajorVersion}.1.1`, + }, + env: { + NPM_CONFIG_REGISTRY: "NPM_CONFIG_REGISTRY", + }, + }, + fs: memfs as any, + path: nodePath, + }; + + await run(app, ["node-version-test"], context as LocalContext); + + const result = { + stdout: stdout.text, + stderr: stderr.text, + files: vol.toJSON(), + }; + compareToBaseline(this, ApplicationTestResultFormat, result); + expect(fetch.callCount).to.equal(1, "fetch called an unexpected number of times"); + expect(fetch.args[0]?.[0]).to.equal( + "NPM_CONFIG_REGISTRY/@types/node", + "fetch called with unexpected argument", + ); + }); + }); + }); }); diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/exact version exists for types.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/exact version exists for types.txt new file mode 100644 index 0000000..ffbff15 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/exact version exists for types.txt @@ -0,0 +1,277 @@ +[STDOUT] + +[STDERR] + +[FILES] +::::/home/node-version-test/.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +*.tsbuildinfo +dist + +::::/home/node-version-test/package.json +{ + "name": "node-version-test", + "author": "", + "description": "Stricli command line application", + "license": "MIT", + "type": "module", + "version": "0.0.0", + "files": [ + "dist" + ], + "bin": { + "node-version-test": "dist/cli.js", + "__node-version-test_bash_complete": "dist/bash-complete.js" + }, + "engines": { + "node": ">=30" + }, + "scripts": { + "prebuild": "tsc -p src/tsconfig.json", + "build": "tsup", + "prepublishOnly": "npm run build", + "postinstall": "node-version-test install" + }, + "tsup": { + "entry": [ + "src/bin/cli.ts", + "src/bin/bash-complete.ts" + ], + "format": [ + "esm" + ], + "tsconfig": "src/tsconfig.json", + "clean": true, + "splitting": true, + "minify": true + }, + "dependencies": { + "@stricli/core": "", + "@stricli/auto-complete": "" + }, + "devDependencies": { + "@types/node": "^30.0.0", + "tsup": "^6.7.0", + "typescript": "5.6.x" + } +} +::::/home/node-version-test/src/app.ts +import { buildApplication, buildRouteMap } from "@stricli/core"; +import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete"; +import { name, version, description } from "../package.json"; +import { subdirCommand } from "./commands/subdir/command"; +import { nestedRoutes } from "./commands/nested/commands"; + +const routes = buildRouteMap({ + routes: { + subdir: subdirCommand, + nested: nestedRoutes, + install: buildInstallCommand("node-version-test", { bash: "__node-version-test_bash_complete" }), + uninstall: buildUninstallCommand("node-version-test", { bash: true }), + }, + docs: { + brief: description, + hideRoute: { + install: true, + uninstall: true, + }, + }, +}); + +export const app = buildApplication(routes, { + name, + versionInfo: { + currentVersion: version, + }, +}); + +::::/home/node-version-test/src/bin/bash-complete.ts +#!/usr/bin/env node +import { proposeCompletions } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +const inputs = process.argv.slice(3); +if (process.env["COMP_LINE"]?.endsWith(" ")) { + inputs.push(""); +} +await proposeCompletions(app, inputs, buildContext(process)); +try { + for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) { + process.stdout.write(`${completion}\n`); + } +} catch { + // ignore +} + +::::/home/node-version-test/src/bin/cli.ts +#!/usr/bin/env node +import { run } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +await run(app, process.argv.slice(2), buildContext(process)); + +::::/home/node-version-test/src/commands/nested/commands.ts +import { buildCommand, buildRouteMap } from "@stricli/core"; + +export const fooCommand = buildCommand({ + loader: async () => { + const { foo } = await import("./impl"); + return foo; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested foo command", + }, +}); + +export const barCommand = buildCommand({ + loader: async () => { + const { bar } = await import("./impl"); + return bar; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested bar command", + }, +}); + +export const nestedRoutes = buildRouteMap({ + routes: { + foo: fooCommand, + bar: barCommand, + }, + docs: { + brief: "Nested commands", + }, +}); + +::::/home/node-version-test/src/commands/nested/impl.ts +import type { LocalContext } from "../../context"; + +interface FooCommandFlags { + // ... +} + +export async function foo(this: LocalContext, flags: FooCommandFlags): Promise { + // ... +} + +interface BarCommandFlags { + // ... +} + +export async function bar(this: LocalContext, flags: BarCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/commands/subdir/command.ts +import { buildCommand } from "@stricli/core"; + +export const subdirCommand = buildCommand({ + loader: async () => import("./impl"), + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Command in subdirectory", + }, +}); + +::::/home/node-version-test/src/commands/subdir/impl.ts +import type { LocalContext } from "../../context"; + +interface SubdirCommandFlags { + // ... +} + +export default async function(this: LocalContext, flags: SubdirCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/context.ts +import type { CommandContext } from "@stricli/core"; +import type { StricliAutoCompleteContext } from "@stricli/auto-complete"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +export interface LocalContext extends CommandContext, StricliAutoCompleteContext { + readonly process: NodeJS.Process; + // ... +} + +export function buildContext(process: NodeJS.Process): LocalContext { + return { + process, + os, + fs, + path, + }; +} + +::::/home/node-version-test/src/tsconfig.json +{ + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "types": [ + "node" + ], + "resolveJsonModule": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": [ + "esnext" + ], + "skipLibCheck": true, + "strict": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true + }, + "include": [ + "**/*" + ], + "exclude": [] +} \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/major version does not exist in registry, picks highest even major.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/major version does not exist in registry, picks highest even major.txt new file mode 100644 index 0000000..45fc495 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/major version does not exist in registry, picks highest even major.txt @@ -0,0 +1,278 @@ +[STDOUT] + +[STDERR] +No version of @types/node found with major 30, falling back to 20.x +Rerun this command with the hidden flag --node-version to manually specify the Node.js major version +[FILES] +::::/home/node-version-test/.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +*.tsbuildinfo +dist + +::::/home/node-version-test/package.json +{ + "name": "node-version-test", + "author": "", + "description": "Stricli command line application", + "license": "MIT", + "type": "module", + "version": "0.0.0", + "files": [ + "dist" + ], + "bin": { + "node-version-test": "dist/cli.js", + "__node-version-test_bash_complete": "dist/bash-complete.js" + }, + "engines": { + "node": ">=30" + }, + "scripts": { + "prebuild": "tsc -p src/tsconfig.json", + "build": "tsup", + "prepublishOnly": "npm run build", + "postinstall": "node-version-test install" + }, + "tsup": { + "entry": [ + "src/bin/cli.ts", + "src/bin/bash-complete.ts" + ], + "format": [ + "esm" + ], + "tsconfig": "src/tsconfig.json", + "clean": true, + "splitting": true, + "minify": true + }, + "dependencies": { + "@stricli/core": "", + "@stricli/auto-complete": "" + }, + "devDependencies": { + "@types/node": "20.x", + "tsup": "^6.7.0", + "typescript": "5.6.x" + } +} +::::/home/node-version-test/src/app.ts +import { buildApplication, buildRouteMap } from "@stricli/core"; +import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete"; +import { name, version, description } from "../package.json"; +import { subdirCommand } from "./commands/subdir/command"; +import { nestedRoutes } from "./commands/nested/commands"; + +const routes = buildRouteMap({ + routes: { + subdir: subdirCommand, + nested: nestedRoutes, + install: buildInstallCommand("node-version-test", { bash: "__node-version-test_bash_complete" }), + uninstall: buildUninstallCommand("node-version-test", { bash: true }), + }, + docs: { + brief: description, + hideRoute: { + install: true, + uninstall: true, + }, + }, +}); + +export const app = buildApplication(routes, { + name, + versionInfo: { + currentVersion: version, + }, +}); + +::::/home/node-version-test/src/bin/bash-complete.ts +#!/usr/bin/env node +import { proposeCompletions } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +const inputs = process.argv.slice(3); +if (process.env["COMP_LINE"]?.endsWith(" ")) { + inputs.push(""); +} +await proposeCompletions(app, inputs, buildContext(process)); +try { + for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) { + process.stdout.write(`${completion}\n`); + } +} catch { + // ignore +} + +::::/home/node-version-test/src/bin/cli.ts +#!/usr/bin/env node +import { run } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +await run(app, process.argv.slice(2), buildContext(process)); + +::::/home/node-version-test/src/commands/nested/commands.ts +import { buildCommand, buildRouteMap } from "@stricli/core"; + +export const fooCommand = buildCommand({ + loader: async () => { + const { foo } = await import("./impl"); + return foo; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested foo command", + }, +}); + +export const barCommand = buildCommand({ + loader: async () => { + const { bar } = await import("./impl"); + return bar; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested bar command", + }, +}); + +export const nestedRoutes = buildRouteMap({ + routes: { + foo: fooCommand, + bar: barCommand, + }, + docs: { + brief: "Nested commands", + }, +}); + +::::/home/node-version-test/src/commands/nested/impl.ts +import type { LocalContext } from "../../context"; + +interface FooCommandFlags { + // ... +} + +export async function foo(this: LocalContext, flags: FooCommandFlags): Promise { + // ... +} + +interface BarCommandFlags { + // ... +} + +export async function bar(this: LocalContext, flags: BarCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/commands/subdir/command.ts +import { buildCommand } from "@stricli/core"; + +export const subdirCommand = buildCommand({ + loader: async () => import("./impl"), + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Command in subdirectory", + }, +}); + +::::/home/node-version-test/src/commands/subdir/impl.ts +import type { LocalContext } from "../../context"; + +interface SubdirCommandFlags { + // ... +} + +export default async function(this: LocalContext, flags: SubdirCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/context.ts +import type { CommandContext } from "@stricli/core"; +import type { StricliAutoCompleteContext } from "@stricli/auto-complete"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +export interface LocalContext extends CommandContext, StricliAutoCompleteContext { + readonly process: NodeJS.Process; + // ... +} + +export function buildContext(process: NodeJS.Process): LocalContext { + return { + process, + os, + fs, + path, + }; +} + +::::/home/node-version-test/src/tsconfig.json +{ + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "types": [ + "node" + ], + "resolveJsonModule": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": [ + "esnext" + ], + "skipLibCheck": true, + "strict": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true + }, + "include": [ + "**/*" + ], + "exclude": [] +} \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/major version exists in registry.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/major version exists in registry.txt new file mode 100644 index 0000000..7ea39c3 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/major version exists in registry.txt @@ -0,0 +1,277 @@ +[STDOUT] + +[STDERR] + +[FILES] +::::/home/node-version-test/.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +*.tsbuildinfo +dist + +::::/home/node-version-test/package.json +{ + "name": "node-version-test", + "author": "", + "description": "Stricli command line application", + "license": "MIT", + "type": "module", + "version": "0.0.0", + "files": [ + "dist" + ], + "bin": { + "node-version-test": "dist/cli.js", + "__node-version-test_bash_complete": "dist/bash-complete.js" + }, + "engines": { + "node": ">=30" + }, + "scripts": { + "prebuild": "tsc -p src/tsconfig.json", + "build": "tsup", + "prepublishOnly": "npm run build", + "postinstall": "node-version-test install" + }, + "tsup": { + "entry": [ + "src/bin/cli.ts", + "src/bin/bash-complete.ts" + ], + "format": [ + "esm" + ], + "tsconfig": "src/tsconfig.json", + "clean": true, + "splitting": true, + "minify": true + }, + "dependencies": { + "@stricli/core": "", + "@stricli/auto-complete": "" + }, + "devDependencies": { + "@types/node": "30.x", + "tsup": "^6.7.0", + "typescript": "5.6.x" + } +} +::::/home/node-version-test/src/app.ts +import { buildApplication, buildRouteMap } from "@stricli/core"; +import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete"; +import { name, version, description } from "../package.json"; +import { subdirCommand } from "./commands/subdir/command"; +import { nestedRoutes } from "./commands/nested/commands"; + +const routes = buildRouteMap({ + routes: { + subdir: subdirCommand, + nested: nestedRoutes, + install: buildInstallCommand("node-version-test", { bash: "__node-version-test_bash_complete" }), + uninstall: buildUninstallCommand("node-version-test", { bash: true }), + }, + docs: { + brief: description, + hideRoute: { + install: true, + uninstall: true, + }, + }, +}); + +export const app = buildApplication(routes, { + name, + versionInfo: { + currentVersion: version, + }, +}); + +::::/home/node-version-test/src/bin/bash-complete.ts +#!/usr/bin/env node +import { proposeCompletions } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +const inputs = process.argv.slice(3); +if (process.env["COMP_LINE"]?.endsWith(" ")) { + inputs.push(""); +} +await proposeCompletions(app, inputs, buildContext(process)); +try { + for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) { + process.stdout.write(`${completion}\n`); + } +} catch { + // ignore +} + +::::/home/node-version-test/src/bin/cli.ts +#!/usr/bin/env node +import { run } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +await run(app, process.argv.slice(2), buildContext(process)); + +::::/home/node-version-test/src/commands/nested/commands.ts +import { buildCommand, buildRouteMap } from "@stricli/core"; + +export const fooCommand = buildCommand({ + loader: async () => { + const { foo } = await import("./impl"); + return foo; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested foo command", + }, +}); + +export const barCommand = buildCommand({ + loader: async () => { + const { bar } = await import("./impl"); + return bar; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested bar command", + }, +}); + +export const nestedRoutes = buildRouteMap({ + routes: { + foo: fooCommand, + bar: barCommand, + }, + docs: { + brief: "Nested commands", + }, +}); + +::::/home/node-version-test/src/commands/nested/impl.ts +import type { LocalContext } from "../../context"; + +interface FooCommandFlags { + // ... +} + +export async function foo(this: LocalContext, flags: FooCommandFlags): Promise { + // ... +} + +interface BarCommandFlags { + // ... +} + +export async function bar(this: LocalContext, flags: BarCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/commands/subdir/command.ts +import { buildCommand } from "@stricli/core"; + +export const subdirCommand = buildCommand({ + loader: async () => import("./impl"), + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Command in subdirectory", + }, +}); + +::::/home/node-version-test/src/commands/subdir/impl.ts +import type { LocalContext } from "../../context"; + +interface SubdirCommandFlags { + // ... +} + +export default async function(this: LocalContext, flags: SubdirCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/context.ts +import type { CommandContext } from "@stricli/core"; +import type { StricliAutoCompleteContext } from "@stricli/auto-complete"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +export interface LocalContext extends CommandContext, StricliAutoCompleteContext { + readonly process: NodeJS.Process; + // ... +} + +export function buildContext(process: NodeJS.Process): LocalContext { + return { + process, + os, + fs, + path, + }; +} + +::::/home/node-version-test/src/tsconfig.json +{ + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "types": [ + "node" + ], + "resolveJsonModule": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": [ + "esnext" + ], + "skipLibCheck": true, + "strict": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true + }, + "include": [ + "**/*" + ], + "exclude": [] +} \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/version discovery skipped when --node-version is provided.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/version discovery skipped when --node-version is provided.txt new file mode 100644 index 0000000..34218d2 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/version discovery skipped when --node-version is provided.txt @@ -0,0 +1,277 @@ +[STDOUT] + +[STDERR] + +[FILES] +::::/home/node-version-test/.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +*.tsbuildinfo +dist + +::::/home/node-version-test/package.json +{ + "name": "node-version-test", + "author": "", + "description": "Stricli command line application", + "license": "MIT", + "type": "module", + "version": "0.0.0", + "files": [ + "dist" + ], + "bin": { + "node-version-test": "dist/cli.js", + "__node-version-test_bash_complete": "dist/bash-complete.js" + }, + "engines": { + "node": ">=31" + }, + "scripts": { + "prebuild": "tsc -p src/tsconfig.json", + "build": "tsup", + "prepublishOnly": "npm run build", + "postinstall": "node-version-test install" + }, + "tsup": { + "entry": [ + "src/bin/cli.ts", + "src/bin/bash-complete.ts" + ], + "format": [ + "esm" + ], + "tsconfig": "src/tsconfig.json", + "clean": true, + "splitting": true, + "minify": true + }, + "dependencies": { + "@stricli/core": "", + "@stricli/auto-complete": "" + }, + "devDependencies": { + "@types/node": "31.x", + "tsup": "^6.7.0", + "typescript": "5.6.x" + } +} +::::/home/node-version-test/src/app.ts +import { buildApplication, buildRouteMap } from "@stricli/core"; +import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete"; +import { name, version, description } from "../package.json"; +import { subdirCommand } from "./commands/subdir/command"; +import { nestedRoutes } from "./commands/nested/commands"; + +const routes = buildRouteMap({ + routes: { + subdir: subdirCommand, + nested: nestedRoutes, + install: buildInstallCommand("node-version-test", { bash: "__node-version-test_bash_complete" }), + uninstall: buildUninstallCommand("node-version-test", { bash: true }), + }, + docs: { + brief: description, + hideRoute: { + install: true, + uninstall: true, + }, + }, +}); + +export const app = buildApplication(routes, { + name, + versionInfo: { + currentVersion: version, + }, +}); + +::::/home/node-version-test/src/bin/bash-complete.ts +#!/usr/bin/env node +import { proposeCompletions } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +const inputs = process.argv.slice(3); +if (process.env["COMP_LINE"]?.endsWith(" ")) { + inputs.push(""); +} +await proposeCompletions(app, inputs, buildContext(process)); +try { + for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) { + process.stdout.write(`${completion}\n`); + } +} catch { + // ignore +} + +::::/home/node-version-test/src/bin/cli.ts +#!/usr/bin/env node +import { run } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +await run(app, process.argv.slice(2), buildContext(process)); + +::::/home/node-version-test/src/commands/nested/commands.ts +import { buildCommand, buildRouteMap } from "@stricli/core"; + +export const fooCommand = buildCommand({ + loader: async () => { + const { foo } = await import("./impl"); + return foo; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested foo command", + }, +}); + +export const barCommand = buildCommand({ + loader: async () => { + const { bar } = await import("./impl"); + return bar; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested bar command", + }, +}); + +export const nestedRoutes = buildRouteMap({ + routes: { + foo: fooCommand, + bar: barCommand, + }, + docs: { + brief: "Nested commands", + }, +}); + +::::/home/node-version-test/src/commands/nested/impl.ts +import type { LocalContext } from "../../context"; + +interface FooCommandFlags { + // ... +} + +export async function foo(this: LocalContext, flags: FooCommandFlags): Promise { + // ... +} + +interface BarCommandFlags { + // ... +} + +export async function bar(this: LocalContext, flags: BarCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/commands/subdir/command.ts +import { buildCommand } from "@stricli/core"; + +export const subdirCommand = buildCommand({ + loader: async () => import("./impl"), + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Command in subdirectory", + }, +}); + +::::/home/node-version-test/src/commands/subdir/impl.ts +import type { LocalContext } from "../../context"; + +interface SubdirCommandFlags { + // ... +} + +export default async function(this: LocalContext, flags: SubdirCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/context.ts +import type { CommandContext } from "@stricli/core"; +import type { StricliAutoCompleteContext } from "@stricli/auto-complete"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +export interface LocalContext extends CommandContext, StricliAutoCompleteContext { + readonly process: NodeJS.Process; + // ... +} + +export function buildContext(process: NodeJS.Process): LocalContext { + return { + process, + os, + fs, + path, + }; +} + +::::/home/node-version-test/src/tsconfig.json +{ + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "types": [ + "node" + ], + "resolveJsonModule": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": [ + "esnext" + ], + "skipLibCheck": true, + "strict": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true + }, + "include": [ + "**/*" + ], + "exclude": [] +} \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/NPM_EXECPATH throws an error.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/NPM_EXECPATH throws an error.txt new file mode 100644 index 0000000..3dc26af --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/NPM_EXECPATH throws an error.txt @@ -0,0 +1,7 @@ +[STDOUT] + +[STDERR] +Command failed, Error: Failed to execute NPM_EXECPATH + at Context. (#/tests/app.spec.ts:?:?) + +[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/no check for safe major version.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/no check for safe major version.txt new file mode 100644 index 0000000..7b29d64 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/no check for safe major version.txt @@ -0,0 +1,277 @@ +[STDOUT] + +[STDERR] + +[FILES] +::::/home/node-version-test/.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +*.tsbuildinfo +dist + +::::/home/node-version-test/package.json +{ + "name": "node-version-test", + "author": "", + "description": "Stricli command line application", + "license": "MIT", + "type": "module", + "version": "0.0.0", + "files": [ + "dist" + ], + "bin": { + "node-version-test": "dist/cli.js", + "__node-version-test_bash_complete": "dist/bash-complete.js" + }, + "engines": { + "node": ">=20" + }, + "scripts": { + "prebuild": "tsc -p src/tsconfig.json", + "build": "tsup", + "prepublishOnly": "npm run build", + "postinstall": "node-version-test install" + }, + "tsup": { + "entry": [ + "src/bin/cli.ts", + "src/bin/bash-complete.ts" + ], + "format": [ + "esm" + ], + "tsconfig": "src/tsconfig.json", + "clean": true, + "splitting": true, + "minify": true + }, + "dependencies": { + "@stricli/core": "", + "@stricli/auto-complete": "" + }, + "devDependencies": { + "@types/node": "20.x", + "tsup": "^6.7.0", + "typescript": "5.6.x" + } +} +::::/home/node-version-test/src/app.ts +import { buildApplication, buildRouteMap } from "@stricli/core"; +import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete"; +import { name, version, description } from "../package.json"; +import { subdirCommand } from "./commands/subdir/command"; +import { nestedRoutes } from "./commands/nested/commands"; + +const routes = buildRouteMap({ + routes: { + subdir: subdirCommand, + nested: nestedRoutes, + install: buildInstallCommand("node-version-test", { bash: "__node-version-test_bash_complete" }), + uninstall: buildUninstallCommand("node-version-test", { bash: true }), + }, + docs: { + brief: description, + hideRoute: { + install: true, + uninstall: true, + }, + }, +}); + +export const app = buildApplication(routes, { + name, + versionInfo: { + currentVersion: version, + }, +}); + +::::/home/node-version-test/src/bin/bash-complete.ts +#!/usr/bin/env node +import { proposeCompletions } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +const inputs = process.argv.slice(3); +if (process.env["COMP_LINE"]?.endsWith(" ")) { + inputs.push(""); +} +await proposeCompletions(app, inputs, buildContext(process)); +try { + for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) { + process.stdout.write(`${completion}\n`); + } +} catch { + // ignore +} + +::::/home/node-version-test/src/bin/cli.ts +#!/usr/bin/env node +import { run } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +await run(app, process.argv.slice(2), buildContext(process)); + +::::/home/node-version-test/src/commands/nested/commands.ts +import { buildCommand, buildRouteMap } from "@stricli/core"; + +export const fooCommand = buildCommand({ + loader: async () => { + const { foo } = await import("./impl"); + return foo; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested foo command", + }, +}); + +export const barCommand = buildCommand({ + loader: async () => { + const { bar } = await import("./impl"); + return bar; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested bar command", + }, +}); + +export const nestedRoutes = buildRouteMap({ + routes: { + foo: fooCommand, + bar: barCommand, + }, + docs: { + brief: "Nested commands", + }, +}); + +::::/home/node-version-test/src/commands/nested/impl.ts +import type { LocalContext } from "../../context"; + +interface FooCommandFlags { + // ... +} + +export async function foo(this: LocalContext, flags: FooCommandFlags): Promise { + // ... +} + +interface BarCommandFlags { + // ... +} + +export async function bar(this: LocalContext, flags: BarCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/commands/subdir/command.ts +import { buildCommand } from "@stricli/core"; + +export const subdirCommand = buildCommand({ + loader: async () => import("./impl"), + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Command in subdirectory", + }, +}); + +::::/home/node-version-test/src/commands/subdir/impl.ts +import type { LocalContext } from "../../context"; + +interface SubdirCommandFlags { + // ... +} + +export default async function(this: LocalContext, flags: SubdirCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/context.ts +import type { CommandContext } from "@stricli/core"; +import type { StricliAutoCompleteContext } from "@stricli/auto-complete"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +export interface LocalContext extends CommandContext, StricliAutoCompleteContext { + readonly process: NodeJS.Process; + // ... +} + +export function buildContext(process: NodeJS.Process): LocalContext { + return { + process, + os, + fs, + path, + }; +} + +::::/home/node-version-test/src/tsconfig.json +{ + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "types": [ + "node" + ], + "resolveJsonModule": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": [ + "esnext" + ], + "skipLibCheck": true, + "strict": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true + }, + "include": [ + "**/*" + ], + "exclude": [] +} \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/reads registry direct from NPM_CONFIG_REGISTRY, URL ends with slash.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/reads registry direct from NPM_CONFIG_REGISTRY, URL ends with slash.txt new file mode 100644 index 0000000..960cff5 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/reads registry direct from NPM_CONFIG_REGISTRY, URL ends with slash.txt @@ -0,0 +1,278 @@ +[STDOUT] + +[STDERR] +Unable to determine version of @types/node for 30.0.0, assuming 30.x +Rerun this command with the hidden flag --node-version to manually specify the Node.js major version +[FILES] +::::/home/node-version-test/.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +*.tsbuildinfo +dist + +::::/home/node-version-test/package.json +{ + "name": "node-version-test", + "author": "", + "description": "Stricli command line application", + "license": "MIT", + "type": "module", + "version": "0.0.0", + "files": [ + "dist" + ], + "bin": { + "node-version-test": "dist/cli.js", + "__node-version-test_bash_complete": "dist/bash-complete.js" + }, + "engines": { + "node": ">=30" + }, + "scripts": { + "prebuild": "tsc -p src/tsconfig.json", + "build": "tsup", + "prepublishOnly": "npm run build", + "postinstall": "node-version-test install" + }, + "tsup": { + "entry": [ + "src/bin/cli.ts", + "src/bin/bash-complete.ts" + ], + "format": [ + "esm" + ], + "tsconfig": "src/tsconfig.json", + "clean": true, + "splitting": true, + "minify": true + }, + "dependencies": { + "@stricli/core": "", + "@stricli/auto-complete": "" + }, + "devDependencies": { + "@types/node": "30.x", + "tsup": "^6.7.0", + "typescript": "5.6.x" + } +} +::::/home/node-version-test/src/app.ts +import { buildApplication, buildRouteMap } from "@stricli/core"; +import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete"; +import { name, version, description } from "../package.json"; +import { subdirCommand } from "./commands/subdir/command"; +import { nestedRoutes } from "./commands/nested/commands"; + +const routes = buildRouteMap({ + routes: { + subdir: subdirCommand, + nested: nestedRoutes, + install: buildInstallCommand("node-version-test", { bash: "__node-version-test_bash_complete" }), + uninstall: buildUninstallCommand("node-version-test", { bash: true }), + }, + docs: { + brief: description, + hideRoute: { + install: true, + uninstall: true, + }, + }, +}); + +export const app = buildApplication(routes, { + name, + versionInfo: { + currentVersion: version, + }, +}); + +::::/home/node-version-test/src/bin/bash-complete.ts +#!/usr/bin/env node +import { proposeCompletions } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +const inputs = process.argv.slice(3); +if (process.env["COMP_LINE"]?.endsWith(" ")) { + inputs.push(""); +} +await proposeCompletions(app, inputs, buildContext(process)); +try { + for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) { + process.stdout.write(`${completion}\n`); + } +} catch { + // ignore +} + +::::/home/node-version-test/src/bin/cli.ts +#!/usr/bin/env node +import { run } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +await run(app, process.argv.slice(2), buildContext(process)); + +::::/home/node-version-test/src/commands/nested/commands.ts +import { buildCommand, buildRouteMap } from "@stricli/core"; + +export const fooCommand = buildCommand({ + loader: async () => { + const { foo } = await import("./impl"); + return foo; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested foo command", + }, +}); + +export const barCommand = buildCommand({ + loader: async () => { + const { bar } = await import("./impl"); + return bar; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested bar command", + }, +}); + +export const nestedRoutes = buildRouteMap({ + routes: { + foo: fooCommand, + bar: barCommand, + }, + docs: { + brief: "Nested commands", + }, +}); + +::::/home/node-version-test/src/commands/nested/impl.ts +import type { LocalContext } from "../../context"; + +interface FooCommandFlags { + // ... +} + +export async function foo(this: LocalContext, flags: FooCommandFlags): Promise { + // ... +} + +interface BarCommandFlags { + // ... +} + +export async function bar(this: LocalContext, flags: BarCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/commands/subdir/command.ts +import { buildCommand } from "@stricli/core"; + +export const subdirCommand = buildCommand({ + loader: async () => import("./impl"), + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Command in subdirectory", + }, +}); + +::::/home/node-version-test/src/commands/subdir/impl.ts +import type { LocalContext } from "../../context"; + +interface SubdirCommandFlags { + // ... +} + +export default async function(this: LocalContext, flags: SubdirCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/context.ts +import type { CommandContext } from "@stricli/core"; +import type { StricliAutoCompleteContext } from "@stricli/auto-complete"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +export interface LocalContext extends CommandContext, StricliAutoCompleteContext { + readonly process: NodeJS.Process; + // ... +} + +export function buildContext(process: NodeJS.Process): LocalContext { + return { + process, + os, + fs, + path, + }; +} + +::::/home/node-version-test/src/tsconfig.json +{ + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "types": [ + "node" + ], + "resolveJsonModule": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": [ + "esnext" + ], + "skipLibCheck": true, + "strict": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true + }, + "include": [ + "**/*" + ], + "exclude": [] +} \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/reads registry direct from NPM_CONFIG_REGISTRY.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/reads registry direct from NPM_CONFIG_REGISTRY.txt new file mode 100644 index 0000000..960cff5 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/reads registry direct from NPM_CONFIG_REGISTRY.txt @@ -0,0 +1,278 @@ +[STDOUT] + +[STDERR] +Unable to determine version of @types/node for 30.0.0, assuming 30.x +Rerun this command with the hidden flag --node-version to manually specify the Node.js major version +[FILES] +::::/home/node-version-test/.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +*.tsbuildinfo +dist + +::::/home/node-version-test/package.json +{ + "name": "node-version-test", + "author": "", + "description": "Stricli command line application", + "license": "MIT", + "type": "module", + "version": "0.0.0", + "files": [ + "dist" + ], + "bin": { + "node-version-test": "dist/cli.js", + "__node-version-test_bash_complete": "dist/bash-complete.js" + }, + "engines": { + "node": ">=30" + }, + "scripts": { + "prebuild": "tsc -p src/tsconfig.json", + "build": "tsup", + "prepublishOnly": "npm run build", + "postinstall": "node-version-test install" + }, + "tsup": { + "entry": [ + "src/bin/cli.ts", + "src/bin/bash-complete.ts" + ], + "format": [ + "esm" + ], + "tsconfig": "src/tsconfig.json", + "clean": true, + "splitting": true, + "minify": true + }, + "dependencies": { + "@stricli/core": "", + "@stricli/auto-complete": "" + }, + "devDependencies": { + "@types/node": "30.x", + "tsup": "^6.7.0", + "typescript": "5.6.x" + } +} +::::/home/node-version-test/src/app.ts +import { buildApplication, buildRouteMap } from "@stricli/core"; +import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete"; +import { name, version, description } from "../package.json"; +import { subdirCommand } from "./commands/subdir/command"; +import { nestedRoutes } from "./commands/nested/commands"; + +const routes = buildRouteMap({ + routes: { + subdir: subdirCommand, + nested: nestedRoutes, + install: buildInstallCommand("node-version-test", { bash: "__node-version-test_bash_complete" }), + uninstall: buildUninstallCommand("node-version-test", { bash: true }), + }, + docs: { + brief: description, + hideRoute: { + install: true, + uninstall: true, + }, + }, +}); + +export const app = buildApplication(routes, { + name, + versionInfo: { + currentVersion: version, + }, +}); + +::::/home/node-version-test/src/bin/bash-complete.ts +#!/usr/bin/env node +import { proposeCompletions } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +const inputs = process.argv.slice(3); +if (process.env["COMP_LINE"]?.endsWith(" ")) { + inputs.push(""); +} +await proposeCompletions(app, inputs, buildContext(process)); +try { + for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) { + process.stdout.write(`${completion}\n`); + } +} catch { + // ignore +} + +::::/home/node-version-test/src/bin/cli.ts +#!/usr/bin/env node +import { run } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +await run(app, process.argv.slice(2), buildContext(process)); + +::::/home/node-version-test/src/commands/nested/commands.ts +import { buildCommand, buildRouteMap } from "@stricli/core"; + +export const fooCommand = buildCommand({ + loader: async () => { + const { foo } = await import("./impl"); + return foo; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested foo command", + }, +}); + +export const barCommand = buildCommand({ + loader: async () => { + const { bar } = await import("./impl"); + return bar; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested bar command", + }, +}); + +export const nestedRoutes = buildRouteMap({ + routes: { + foo: fooCommand, + bar: barCommand, + }, + docs: { + brief: "Nested commands", + }, +}); + +::::/home/node-version-test/src/commands/nested/impl.ts +import type { LocalContext } from "../../context"; + +interface FooCommandFlags { + // ... +} + +export async function foo(this: LocalContext, flags: FooCommandFlags): Promise { + // ... +} + +interface BarCommandFlags { + // ... +} + +export async function bar(this: LocalContext, flags: BarCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/commands/subdir/command.ts +import { buildCommand } from "@stricli/core"; + +export const subdirCommand = buildCommand({ + loader: async () => import("./impl"), + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Command in subdirectory", + }, +}); + +::::/home/node-version-test/src/commands/subdir/impl.ts +import type { LocalContext } from "../../context"; + +interface SubdirCommandFlags { + // ... +} + +export default async function(this: LocalContext, flags: SubdirCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/context.ts +import type { CommandContext } from "@stricli/core"; +import type { StricliAutoCompleteContext } from "@stricli/auto-complete"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +export interface LocalContext extends CommandContext, StricliAutoCompleteContext { + readonly process: NodeJS.Process; + // ... +} + +export function buildContext(process: NodeJS.Process): LocalContext { + return { + process, + os, + fs, + path, + }; +} + +::::/home/node-version-test/src/tsconfig.json +{ + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "types": [ + "node" + ], + "resolveJsonModule": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": [ + "esnext" + ], + "skipLibCheck": true, + "strict": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true + }, + "include": [ + "**/*" + ], + "exclude": [] +} \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/registry data has no versions.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/registry data has no versions.txt new file mode 100644 index 0000000..960cff5 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/registry data has no versions.txt @@ -0,0 +1,278 @@ +[STDOUT] + +[STDERR] +Unable to determine version of @types/node for 30.0.0, assuming 30.x +Rerun this command with the hidden flag --node-version to manually specify the Node.js major version +[FILES] +::::/home/node-version-test/.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +*.tsbuildinfo +dist + +::::/home/node-version-test/package.json +{ + "name": "node-version-test", + "author": "", + "description": "Stricli command line application", + "license": "MIT", + "type": "module", + "version": "0.0.0", + "files": [ + "dist" + ], + "bin": { + "node-version-test": "dist/cli.js", + "__node-version-test_bash_complete": "dist/bash-complete.js" + }, + "engines": { + "node": ">=30" + }, + "scripts": { + "prebuild": "tsc -p src/tsconfig.json", + "build": "tsup", + "prepublishOnly": "npm run build", + "postinstall": "node-version-test install" + }, + "tsup": { + "entry": [ + "src/bin/cli.ts", + "src/bin/bash-complete.ts" + ], + "format": [ + "esm" + ], + "tsconfig": "src/tsconfig.json", + "clean": true, + "splitting": true, + "minify": true + }, + "dependencies": { + "@stricli/core": "", + "@stricli/auto-complete": "" + }, + "devDependencies": { + "@types/node": "30.x", + "tsup": "^6.7.0", + "typescript": "5.6.x" + } +} +::::/home/node-version-test/src/app.ts +import { buildApplication, buildRouteMap } from "@stricli/core"; +import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete"; +import { name, version, description } from "../package.json"; +import { subdirCommand } from "./commands/subdir/command"; +import { nestedRoutes } from "./commands/nested/commands"; + +const routes = buildRouteMap({ + routes: { + subdir: subdirCommand, + nested: nestedRoutes, + install: buildInstallCommand("node-version-test", { bash: "__node-version-test_bash_complete" }), + uninstall: buildUninstallCommand("node-version-test", { bash: true }), + }, + docs: { + brief: description, + hideRoute: { + install: true, + uninstall: true, + }, + }, +}); + +export const app = buildApplication(routes, { + name, + versionInfo: { + currentVersion: version, + }, +}); + +::::/home/node-version-test/src/bin/bash-complete.ts +#!/usr/bin/env node +import { proposeCompletions } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +const inputs = process.argv.slice(3); +if (process.env["COMP_LINE"]?.endsWith(" ")) { + inputs.push(""); +} +await proposeCompletions(app, inputs, buildContext(process)); +try { + for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) { + process.stdout.write(`${completion}\n`); + } +} catch { + // ignore +} + +::::/home/node-version-test/src/bin/cli.ts +#!/usr/bin/env node +import { run } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +await run(app, process.argv.slice(2), buildContext(process)); + +::::/home/node-version-test/src/commands/nested/commands.ts +import { buildCommand, buildRouteMap } from "@stricli/core"; + +export const fooCommand = buildCommand({ + loader: async () => { + const { foo } = await import("./impl"); + return foo; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested foo command", + }, +}); + +export const barCommand = buildCommand({ + loader: async () => { + const { bar } = await import("./impl"); + return bar; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested bar command", + }, +}); + +export const nestedRoutes = buildRouteMap({ + routes: { + foo: fooCommand, + bar: barCommand, + }, + docs: { + brief: "Nested commands", + }, +}); + +::::/home/node-version-test/src/commands/nested/impl.ts +import type { LocalContext } from "../../context"; + +interface FooCommandFlags { + // ... +} + +export async function foo(this: LocalContext, flags: FooCommandFlags): Promise { + // ... +} + +interface BarCommandFlags { + // ... +} + +export async function bar(this: LocalContext, flags: BarCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/commands/subdir/command.ts +import { buildCommand } from "@stricli/core"; + +export const subdirCommand = buildCommand({ + loader: async () => import("./impl"), + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Command in subdirectory", + }, +}); + +::::/home/node-version-test/src/commands/subdir/impl.ts +import type { LocalContext } from "../../context"; + +interface SubdirCommandFlags { + // ... +} + +export default async function(this: LocalContext, flags: SubdirCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/context.ts +import type { CommandContext } from "@stricli/core"; +import type { StricliAutoCompleteContext } from "@stricli/auto-complete"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +export interface LocalContext extends CommandContext, StricliAutoCompleteContext { + readonly process: NodeJS.Process; + // ... +} + +export function buildContext(process: NodeJS.Process): LocalContext { + return { + process, + os, + fs, + path, + }; +} + +::::/home/node-version-test/src/tsconfig.json +{ + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "types": [ + "node" + ], + "resolveJsonModule": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": [ + "esnext" + ], + "skipLibCheck": true, + "strict": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true + }, + "include": [ + "**/*" + ], + "exclude": [] +} \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/request to registry throws error.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/request to registry throws error.txt new file mode 100644 index 0000000..5d79089 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/request to registry throws error.txt @@ -0,0 +1,7 @@ +[STDOUT] + +[STDERR] +Command failed, Error: Failed to fetch data from REGISTRY + at Context. (#/tests/app.spec.ts:?:?) + +[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/unable to discover registry from process.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/unable to discover registry from process.txt new file mode 100644 index 0000000..960cff5 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/unable to discover registry from process.txt @@ -0,0 +1,278 @@ +[STDOUT] + +[STDERR] +Unable to determine version of @types/node for 30.0.0, assuming 30.x +Rerun this command with the hidden flag --node-version to manually specify the Node.js major version +[FILES] +::::/home/node-version-test/.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +*.tsbuildinfo +dist + +::::/home/node-version-test/package.json +{ + "name": "node-version-test", + "author": "", + "description": "Stricli command line application", + "license": "MIT", + "type": "module", + "version": "0.0.0", + "files": [ + "dist" + ], + "bin": { + "node-version-test": "dist/cli.js", + "__node-version-test_bash_complete": "dist/bash-complete.js" + }, + "engines": { + "node": ">=30" + }, + "scripts": { + "prebuild": "tsc -p src/tsconfig.json", + "build": "tsup", + "prepublishOnly": "npm run build", + "postinstall": "node-version-test install" + }, + "tsup": { + "entry": [ + "src/bin/cli.ts", + "src/bin/bash-complete.ts" + ], + "format": [ + "esm" + ], + "tsconfig": "src/tsconfig.json", + "clean": true, + "splitting": true, + "minify": true + }, + "dependencies": { + "@stricli/core": "", + "@stricli/auto-complete": "" + }, + "devDependencies": { + "@types/node": "30.x", + "tsup": "^6.7.0", + "typescript": "5.6.x" + } +} +::::/home/node-version-test/src/app.ts +import { buildApplication, buildRouteMap } from "@stricli/core"; +import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete"; +import { name, version, description } from "../package.json"; +import { subdirCommand } from "./commands/subdir/command"; +import { nestedRoutes } from "./commands/nested/commands"; + +const routes = buildRouteMap({ + routes: { + subdir: subdirCommand, + nested: nestedRoutes, + install: buildInstallCommand("node-version-test", { bash: "__node-version-test_bash_complete" }), + uninstall: buildUninstallCommand("node-version-test", { bash: true }), + }, + docs: { + brief: description, + hideRoute: { + install: true, + uninstall: true, + }, + }, +}); + +export const app = buildApplication(routes, { + name, + versionInfo: { + currentVersion: version, + }, +}); + +::::/home/node-version-test/src/bin/bash-complete.ts +#!/usr/bin/env node +import { proposeCompletions } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +const inputs = process.argv.slice(3); +if (process.env["COMP_LINE"]?.endsWith(" ")) { + inputs.push(""); +} +await proposeCompletions(app, inputs, buildContext(process)); +try { + for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) { + process.stdout.write(`${completion}\n`); + } +} catch { + // ignore +} + +::::/home/node-version-test/src/bin/cli.ts +#!/usr/bin/env node +import { run } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +await run(app, process.argv.slice(2), buildContext(process)); + +::::/home/node-version-test/src/commands/nested/commands.ts +import { buildCommand, buildRouteMap } from "@stricli/core"; + +export const fooCommand = buildCommand({ + loader: async () => { + const { foo } = await import("./impl"); + return foo; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested foo command", + }, +}); + +export const barCommand = buildCommand({ + loader: async () => { + const { bar } = await import("./impl"); + return bar; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested bar command", + }, +}); + +export const nestedRoutes = buildRouteMap({ + routes: { + foo: fooCommand, + bar: barCommand, + }, + docs: { + brief: "Nested commands", + }, +}); + +::::/home/node-version-test/src/commands/nested/impl.ts +import type { LocalContext } from "../../context"; + +interface FooCommandFlags { + // ... +} + +export async function foo(this: LocalContext, flags: FooCommandFlags): Promise { + // ... +} + +interface BarCommandFlags { + // ... +} + +export async function bar(this: LocalContext, flags: BarCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/commands/subdir/command.ts +import { buildCommand } from "@stricli/core"; + +export const subdirCommand = buildCommand({ + loader: async () => import("./impl"), + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Command in subdirectory", + }, +}); + +::::/home/node-version-test/src/commands/subdir/impl.ts +import type { LocalContext } from "../../context"; + +interface SubdirCommandFlags { + // ... +} + +export default async function(this: LocalContext, flags: SubdirCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/context.ts +import type { CommandContext } from "@stricli/core"; +import type { StricliAutoCompleteContext } from "@stricli/auto-complete"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +export interface LocalContext extends CommandContext, StricliAutoCompleteContext { + readonly process: NodeJS.Process; + // ... +} + +export function buildContext(process: NodeJS.Process): LocalContext { + return { + process, + os, + fs, + path, + }; +} + +::::/home/node-version-test/src/tsconfig.json +{ + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "types": [ + "node" + ], + "resolveJsonModule": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": [ + "esnext" + ], + "skipLibCheck": true, + "strict": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true + }, + "include": [ + "**/*" + ], + "exclude": [] +} \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/uses NPM_EXECPATH to get registry config value.txt b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/uses NPM_EXECPATH to get registry config value.txt new file mode 100644 index 0000000..960cff5 --- /dev/null +++ b/packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/registry logic/uses NPM_EXECPATH to get registry config value.txt @@ -0,0 +1,278 @@ +[STDOUT] + +[STDERR] +Unable to determine version of @types/node for 30.0.0, assuming 30.x +Rerun this command with the hidden flag --node-version to manually specify the Node.js major version +[FILES] +::::/home/node-version-test/.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +node_modules/ +jspm_packages/ + +*.tsbuildinfo +dist + +::::/home/node-version-test/package.json +{ + "name": "node-version-test", + "author": "", + "description": "Stricli command line application", + "license": "MIT", + "type": "module", + "version": "0.0.0", + "files": [ + "dist" + ], + "bin": { + "node-version-test": "dist/cli.js", + "__node-version-test_bash_complete": "dist/bash-complete.js" + }, + "engines": { + "node": ">=30" + }, + "scripts": { + "prebuild": "tsc -p src/tsconfig.json", + "build": "tsup", + "prepublishOnly": "npm run build", + "postinstall": "node-version-test install" + }, + "tsup": { + "entry": [ + "src/bin/cli.ts", + "src/bin/bash-complete.ts" + ], + "format": [ + "esm" + ], + "tsconfig": "src/tsconfig.json", + "clean": true, + "splitting": true, + "minify": true + }, + "dependencies": { + "@stricli/core": "", + "@stricli/auto-complete": "" + }, + "devDependencies": { + "@types/node": "30.x", + "tsup": "^6.7.0", + "typescript": "5.6.x" + } +} +::::/home/node-version-test/src/app.ts +import { buildApplication, buildRouteMap } from "@stricli/core"; +import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete"; +import { name, version, description } from "../package.json"; +import { subdirCommand } from "./commands/subdir/command"; +import { nestedRoutes } from "./commands/nested/commands"; + +const routes = buildRouteMap({ + routes: { + subdir: subdirCommand, + nested: nestedRoutes, + install: buildInstallCommand("node-version-test", { bash: "__node-version-test_bash_complete" }), + uninstall: buildUninstallCommand("node-version-test", { bash: true }), + }, + docs: { + brief: description, + hideRoute: { + install: true, + uninstall: true, + }, + }, +}); + +export const app = buildApplication(routes, { + name, + versionInfo: { + currentVersion: version, + }, +}); + +::::/home/node-version-test/src/bin/bash-complete.ts +#!/usr/bin/env node +import { proposeCompletions } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +const inputs = process.argv.slice(3); +if (process.env["COMP_LINE"]?.endsWith(" ")) { + inputs.push(""); +} +await proposeCompletions(app, inputs, buildContext(process)); +try { + for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) { + process.stdout.write(`${completion}\n`); + } +} catch { + // ignore +} + +::::/home/node-version-test/src/bin/cli.ts +#!/usr/bin/env node +import { run } from "@stricli/core"; +import { buildContext } from "../context"; +import { app } from "../app"; +await run(app, process.argv.slice(2), buildContext(process)); + +::::/home/node-version-test/src/commands/nested/commands.ts +import { buildCommand, buildRouteMap } from "@stricli/core"; + +export const fooCommand = buildCommand({ + loader: async () => { + const { foo } = await import("./impl"); + return foo; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested foo command", + }, +}); + +export const barCommand = buildCommand({ + loader: async () => { + const { bar } = await import("./impl"); + return bar; + }, + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Nested bar command", + }, +}); + +export const nestedRoutes = buildRouteMap({ + routes: { + foo: fooCommand, + bar: barCommand, + }, + docs: { + brief: "Nested commands", + }, +}); + +::::/home/node-version-test/src/commands/nested/impl.ts +import type { LocalContext } from "../../context"; + +interface FooCommandFlags { + // ... +} + +export async function foo(this: LocalContext, flags: FooCommandFlags): Promise { + // ... +} + +interface BarCommandFlags { + // ... +} + +export async function bar(this: LocalContext, flags: BarCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/commands/subdir/command.ts +import { buildCommand } from "@stricli/core"; + +export const subdirCommand = buildCommand({ + loader: async () => import("./impl"), + parameters: { + positional: { + kind: "tuple", + parameters: [], + }, + }, + docs: { + brief: "Command in subdirectory", + }, +}); + +::::/home/node-version-test/src/commands/subdir/impl.ts +import type { LocalContext } from "../../context"; + +interface SubdirCommandFlags { + // ... +} + +export default async function(this: LocalContext, flags: SubdirCommandFlags): Promise { + // ... +} + +::::/home/node-version-test/src/context.ts +import type { CommandContext } from "@stricli/core"; +import type { StricliAutoCompleteContext } from "@stricli/auto-complete"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +export interface LocalContext extends CommandContext, StricliAutoCompleteContext { + readonly process: NodeJS.Process; + // ... +} + +export function buildContext(process: NodeJS.Process): LocalContext { + return { + process, + os, + fs, + path, + }; +} + +::::/home/node-version-test/src/tsconfig.json +{ + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "types": [ + "node" + ], + "resolveJsonModule": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "lib": [ + "esnext" + ], + "skipLibCheck": true, + "strict": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true + }, + "include": [ + "**/*" + ], + "exclude": [] +} \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/commonjs/additional features/without eslint and prettier.txt b/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/commonjs/additional features/without eslint and prettier.txt deleted file mode 100644 index ea16e8e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/commonjs/additional features/without eslint and prettier.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-eslint - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/commonjs/additional features/without eslint.txt b/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/commonjs/additional features/without eslint.txt deleted file mode 100644 index ea16e8e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/commonjs/additional features/without eslint.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-eslint - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/commonjs/additional features/without prettier.txt b/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/commonjs/additional features/without prettier.txt deleted file mode 100644 index be9942e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/commonjs/additional features/without prettier.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-prettier - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/module [default]/additional features/without eslint and prettier.txt b/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/module [default]/additional features/without eslint and prettier.txt deleted file mode 100644 index ea16e8e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/module [default]/additional features/without eslint and prettier.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-eslint - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/module [default]/additional features/without eslint.txt b/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/module [default]/additional features/without eslint.txt deleted file mode 100644 index ea16e8e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/module [default]/additional features/without eslint.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-eslint - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/module [default]/additional features/without prettier.txt b/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/module [default]/additional features/without prettier.txt deleted file mode 100644 index be9942e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/multi-command/module [default]/additional features/without prettier.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-prettier - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/commonjs/additional features/without eslint and prettier.txt b/packages/create-app/tests/baselines/reference/app/creates new application/single-command/commonjs/additional features/without eslint and prettier.txt deleted file mode 100644 index ea16e8e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/commonjs/additional features/without eslint and prettier.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-eslint - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/commonjs/additional features/without eslint.txt b/packages/create-app/tests/baselines/reference/app/creates new application/single-command/commonjs/additional features/without eslint.txt deleted file mode 100644 index ea16e8e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/commonjs/additional features/without eslint.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-eslint - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/commonjs/additional features/without prettier.txt b/packages/create-app/tests/baselines/reference/app/creates new application/single-command/commonjs/additional features/without prettier.txt deleted file mode 100644 index be9942e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/commonjs/additional features/without prettier.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-prettier - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/module [default]/additional features/without eslint and prettier.txt b/packages/create-app/tests/baselines/reference/app/creates new application/single-command/module [default]/additional features/without eslint and prettier.txt deleted file mode 100644 index ea16e8e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/module [default]/additional features/without eslint and prettier.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-eslint - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/module [default]/additional features/without eslint.txt b/packages/create-app/tests/baselines/reference/app/creates new application/single-command/module [default]/additional features/without eslint.txt deleted file mode 100644 index ea16e8e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/module [default]/additional features/without eslint.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-eslint - -[FILES] \ No newline at end of file diff --git a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/module [default]/additional features/without prettier.txt b/packages/create-app/tests/baselines/reference/app/creates new application/single-command/module [default]/additional features/without prettier.txt deleted file mode 100644 index be9942e..0000000 --- a/packages/create-app/tests/baselines/reference/app/creates new application/single-command/module [default]/additional features/without prettier.txt +++ /dev/null @@ -1,6 +0,0 @@ -[STDOUT] - -[STDERR] -No flag registered for --no-prettier - -[FILES] \ No newline at end of file