From e507566c80f65464ca5907b7259ffd3e395ee978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Wed, 15 Nov 2023 11:35:43 -0500 Subject: [PATCH 1/5] Remove unnecessary splatting of `self` in plugin tests --- ts/project.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ts/project.test.ts b/ts/project.test.ts index 4b024ab4..4813b41a 100644 --- a/ts/project.test.ts +++ b/ts/project.test.ts @@ -61,7 +61,7 @@ describe("Project.add", () => { it("allows adding fields with .add", () => { const project = garn .mkProject({ description: "" }, {}) - .add((self) => ({ ...self, foo: garn.shell("echo foo") })); + .add((_self) => ({ foo: garn.shell("echo foo") })); const output = runExecutable(project.foo); assertSuccess(output); assertStdout(output, "foo\n"); @@ -74,7 +74,7 @@ describe("Project.add", () => { {}, ) .withDevTools([garn.mkPackage(nix.nixRaw`pkgs.hello`, "")]) - .add((self) => ({ ...self, foo: self.shell("hello") })); + .add((self) => ({ foo: self.shell("hello") })); const output = runExecutable(project.foo); assertSuccess(output); assertStdout(output, "Hello, world!\n"); @@ -92,7 +92,7 @@ describe("Project.add", () => { `, }, ) - .add((self) => ({ ...self, foo: self.shell`${self.package}/bin/main` })); + .add((self) => ({ foo: self.shell`${self.package}/bin/main` })); const output = runExecutable(project.foo); assertSuccess(output); assertStdout(output, "main executable\n"); From 530a79ea7a93305149586909fbdffcec4e16e820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Wed, 15 Nov 2023 11:48:52 -0500 Subject: [PATCH 2/5] Add docstring to Plugin type --- ts/mod.ts | 7 ++++++- ts/project.ts | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/ts/mod.ts b/ts/mod.ts index ffaabaeb..95a38f6e 100644 --- a/ts/mod.ts +++ b/ts/mod.ts @@ -9,7 +9,12 @@ export { } from "./environment.ts"; export { type Executable } from "./executable.ts"; export { mkPackage, type Package } from "./package.ts"; -export { mkProject, type Project } from "./project.ts"; +export { + mkProject, + type Project, + type Plugin, + type ProjectHelpers, +} from "./project.ts"; export { editGarnConfig } from "./edit.ts"; // languages diff --git a/ts/project.ts b/ts/project.ts index fd625f5a..9a1981f9 100644 --- a/ts/project.ts +++ b/ts/project.ts @@ -22,11 +22,45 @@ export type ProjectData = { defaultExecutable?: Executable; }; +/** + * `Plugin`s automatically add one or more fields to your project. You can use + * existing plugins to automatically add a few useful fields without having to + * declare them manually yourself. + * + * Here's an example of a simple `Plugin` and how to use it: + * + * ```typescript + * import * as garn from "https://garn.io/ts/v0.0.15/mod.ts"; + * + * const prettier = + * ( + * globPattern: string, + * ): garn.Plugin< + * { formatCheck: garn.Check; format: garn.Executable }, + * garn.ProjectHelpers + * > => + * (p) => + * p + * .withDevTools([ + * garn.mkPackage(garn.nix.nixRaw`pkgs.nodePackages.prettier`, "prettier"), + * ]) + * .addCheck("formatCheck", `prettier --check '${globPattern}'`) + * .addExecutable("format", `prettier --write '${globPattern}'`); + * + * export const frontend = garn.javascript + * .mkNpmProject({ + * src: ".", + * description: "An NPM frontend", + * nodeVersion: "18", + * }) + * .add(prettier("src/*.ts")); + * ``` + */ export type Plugin = ( project: Dependencies & ProjectData, ) => Additions; -type ProjectHelpers = { +export type ProjectHelpers = { /** * Returns a new Project with the provided devtools added to the default * Environment. From 9fe96dd11b718cbad6f9aeda9a2c03e62a3e34ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Wed, 15 Nov 2023 12:51:18 -0500 Subject: [PATCH 3/5] Mimic the recommended importing style in project.test.ts --- ts/project.test.ts | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/ts/project.test.ts b/ts/project.test.ts index 4813b41a..1ab85a10 100644 --- a/ts/project.test.ts +++ b/ts/project.test.ts @@ -1,17 +1,12 @@ -import { Check } from "./check.ts"; -import { Executable } from "./executable.ts"; -import { Plugin, Project } from "./project.ts"; import { describe, it } from "https://deno.land/std@0.206.0/testing/bdd.ts"; import * as garn from "./mod.ts"; -import * as nix from "./nix.ts"; import { assertStdout, assertSuccess, runExecutable } from "./testUtils.ts"; -import { Package } from "./mod.ts"; -const assertTypeIsCheck = (_c: Check) => {}; -const assertTypeIsExecutable = (_e: Executable) => {}; -const assertTypeIsPackage = (_p: Package) => {}; +const assertTypeIsCheck = (_c: garn.Check) => {}; +const assertTypeIsExecutable = (_e: garn.Executable) => {}; +const assertTypeIsPackage = (_p: garn.Package) => {}; -const _testTypeCheckingOfAddCheck = (project: Project) => { +const _testTypeCheckingOfAddCheck = (project: garn.Project) => { const p = project .addExecutable("unrelated1", "true") .addCheck("check", "true") @@ -23,7 +18,7 @@ const _testTypeCheckingOfAddCheck = (project: Project) => { p.check``; }; -const _testTypeCheckingOfAddCheckTemplate = (project: Project) => { +const _testTypeCheckingOfAddCheckTemplate = (project: garn.Project) => { const p = project .addExecutable("unrelated1", "true") .addCheck("check")`true`.addExecutable("unrelated2", "true"); @@ -34,7 +29,7 @@ const _testTypeCheckingOfAddCheckTemplate = (project: Project) => { p.check``; }; -const _testTypeCheckingOfAddExecutable = (project: Project) => { +const _testTypeCheckingOfAddExecutable = (project: garn.Project) => { const p = project .addExecutable("unrelated1", "true") .addExecutable("shell", "true") @@ -46,7 +41,7 @@ const _testTypeCheckingOfAddExecutable = (project: Project) => { p.shell``; }; -const _testTypeCheckingOfAddExecutableTemplate = (project: Project) => { +const _testTypeCheckingOfAddExecutableTemplate = (project: garn.Project) => { const p = project .addExecutable("unrelated1", "true") .addExecutable("shell")`true`.addExecutable("unrelated2", "true"); @@ -73,7 +68,7 @@ describe("Project.add", () => { { description: "", defaultEnvironment: garn.emptyEnvironment }, {}, ) - .withDevTools([garn.mkPackage(nix.nixRaw`pkgs.hello`, "")]) + .withDevTools([garn.mkPackage(garn.nix.nixRaw`pkgs.hello`, "")]) .add((self) => ({ foo: self.shell("hello") })); const output = runExecutable(project.foo); assertSuccess(output); @@ -137,7 +132,7 @@ describe("Project.add", () => { }); it("provides a nice type synonym for plugins that add a field", () => { - const plugin: Plugin<{ addedField: garn.Package }> = (p) => ({ + const plugin: garn.Plugin<{ addedField: garn.Package }> = (_p) => ({ addedField: garn.build``, }); const project = garn @@ -152,7 +147,9 @@ describe("Project.add", () => { }); it("provides a nice type synonym for plugins that add multiple fields", () => { - const plugin: Plugin<{ one: garn.Package; two: garn.Check }> = (p) => ({ + const plugin: garn.Plugin<{ one: garn.Package; two: garn.Check }> = ( + _p, + ) => ({ one: garn.build``, two: garn.check(""), }); @@ -169,9 +166,10 @@ describe("Project.add", () => { }); it("provides a nice interface for plugins that depend on a non-standard field", () => { - const plugin: Plugin<{ addedField: Executable }, { dep: Package }> = ( - p, - ) => ({ + const plugin: garn.Plugin< + { addedField: garn.Executable }, + { dep: garn.Package } + > = (p) => ({ addedField: garn.shell`${p.dep}/bin/whatever`, }); const project = garn @@ -188,7 +186,7 @@ describe("Project.add", () => { }); it("allows overwriting fields", () => { - const plugin: Plugin<{ field: Package }> = (p) => ({ + const plugin: garn.Plugin<{ field: garn.Package }> = (_p) => ({ field: garn.build``, }); const project = garn From fb3d7fa01feefc8e406c1cd5156dfc325b49b2aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Wed, 15 Nov 2023 13:21:37 -0500 Subject: [PATCH 4/5] Move common nixpkgsInput into version.json --- src/Garn/Common.hs | 20 +++++++++++++++++--- src/Garn/GarnConfig.hs | 3 +-- src/Garn/ImportVersion.hs | 25 +++++++++++++++---------- src/Garn/Optparse.hs | 2 +- src/Garn/Utils.hs | 6 ------ ts/internal/version.json | 4 +++- 6 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/Garn/Common.hs b/src/Garn/Common.hs index 09bada73..ce8e96cf 100644 --- a/src/Garn/Common.hs +++ b/src/Garn/Common.hs @@ -1,12 +1,26 @@ -module Garn.Common (nixpkgsInput, nixArgs, currentSystem) where +{-# LANGUAGE TemplateHaskell #-} + +module Garn.Common + ( garnCliVersion, + Garn.Common.nixpkgsInput, + nixArgs, + currentSystem, + ) +where import Cradle (StdoutUntrimmed (..), run) import Data.Aeson (eitherDecode) import Data.String.Conversions (cs) +import Garn.ImportVersion (Versions (..), versionsSplice) + +versionFromJson :: Versions +versionFromJson = $(versionsSplice) + +garnCliVersion :: String +garnCliVersion = tsLibVersion versionFromJson --- | pinned to master on 2023-10-26 nixpkgsInput :: String -nixpkgsInput = "github:NixOS/nixpkgs/6fc7203e423bbf1c8f84cccf1c4818d097612566" +nixpkgsInput = Garn.ImportVersion.nixpkgsInput versionFromJson nixArgs :: [String] nixArgs = diff --git a/src/Garn/GarnConfig.hs b/src/Garn/GarnConfig.hs index 4a1ead4c..9391b00b 100644 --- a/src/Garn/GarnConfig.hs +++ b/src/Garn/GarnConfig.hs @@ -24,9 +24,8 @@ import Data.String.Conversions (cs) import Data.String.Interpolate (i) import Data.String.Interpolate.Util (unindent) import GHC.Generics (Generic) -import Garn.Common (nixArgs, nixpkgsInput) +import Garn.Common (garnCliVersion, nixArgs, nixpkgsInput) import qualified Garn.Errors -import Garn.Utils (garnCliVersion) import System.Directory (doesFileExist, getCurrentDirectory) import System.Exit (ExitCode (..), exitWith) import System.IO (hClose, hPutStr, stderr) diff --git a/src/Garn/ImportVersion.hs b/src/Garn/ImportVersion.hs index 63b6b788..cd1ed963 100644 --- a/src/Garn/ImportVersion.hs +++ b/src/Garn/ImportVersion.hs @@ -1,18 +1,23 @@ -module Garn.ImportVersion (garnVersionSplice) where +{-# LANGUAGE DeriveLift #-} +{-# LANGUAGE TemplateHaskell #-} + +module Garn.ImportVersion (Versions (..), versionsSplice) where import Data.Aeson (FromJSON, eitherDecodeFileStrict') import GHC.Generics (Generic) -import Language.Haskell.TH (Exp (LitE), Lit (StringL), Q, runIO) +import Language.Haskell.TH (Exp, Q, runIO) +import Language.Haskell.TH.Syntax (Lift (..)) -newtype Version = Version - { tsLibVersion :: String +data Versions = Versions + { tsLibVersion :: String, + nixpkgsInput :: String } - deriving stock (Generic) + deriving stock (Generic, Lift) deriving anyclass (FromJSON) -garnVersionSplice :: Q Exp -garnVersionSplice = do - version <- runIO $ eitherDecodeFileStrict' "./ts/internal/version.json" - case version of - Right version -> pure $ LitE $ StringL $ tsLibVersion version +versionsSplice :: Q Exp +versionsSplice = do + versions <- runIO $ eitherDecodeFileStrict' "./ts/internal/version.json" + case versions of + Right (versions :: Versions) -> [|versions|] Left err -> fail err diff --git a/src/Garn/Optparse.hs b/src/Garn/Optparse.hs index b671509b..38d3bd38 100644 --- a/src/Garn/Optparse.hs +++ b/src/Garn/Optparse.hs @@ -12,8 +12,8 @@ module Garn.Optparse where import qualified Data.Map as Map +import Garn.Common (garnCliVersion) import Garn.GarnConfig -import Garn.Utils (garnCliVersion) import Options.Applicative hiding (command) import qualified Options.Applicative as OA import qualified Options.Applicative.Help.Pretty as OA diff --git a/src/Garn/Utils.hs b/src/Garn/Utils.hs index a774a082..a6be6f8b 100644 --- a/src/Garn/Utils.hs +++ b/src/Garn/Utils.hs @@ -1,14 +1,8 @@ -{-# LANGUAGE TemplateHaskell #-} - module Garn.Utils where import Data.String.Conversions (cs) import Debug.Trace (trace) -import Garn.ImportVersion (garnVersionSplice) import Text.Pretty.Simple (pShow) dbg :: (Show a) => a -> a dbg a = trace (cs $ pShow a) a - -garnCliVersion :: String -garnCliVersion = $(garnVersionSplice) diff --git a/ts/internal/version.json b/ts/internal/version.json index a04b78e0..be6266c0 100644 --- a/ts/internal/version.json +++ b/ts/internal/version.json @@ -1,3 +1,5 @@ { - "tsLibVersion": "v0.0.15" + "tsLibVersion": "v0.0.15", + "nixpkgsInputComment": "pinned to master on 2023-10-26", + "nixpkgsInput": "github:NixOS/nixpkgs/6fc7203e423bbf1c8f84cccf1c4818d097612566" } From 4665114dcf8564a0cf1adc58c888e993371efab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Wed, 15 Nov 2023 16:59:20 -0500 Subject: [PATCH 5/5] Tweak jsdocs Co-authored-by: Julian Arni --- ts/project.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/project.ts b/ts/project.ts index 9a1981f9..703c6f35 100644 --- a/ts/project.ts +++ b/ts/project.ts @@ -24,7 +24,7 @@ export type ProjectData = { /** * `Plugin`s automatically add one or more fields to your project. You can use - * existing plugins to automatically add a few useful fields without having to + * existing plugins to automatically add prepackaged functionality to your `Project`. * declare them manually yourself. * * Here's an example of a simple `Plugin` and how to use it: