diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..25abf7018 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: [melkeydev] diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ff04ca1b9..1cf620a6b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,10 +16,10 @@ jobs: uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('docs/requirements.txt') }} diff --git a/.github/workflows/generate-linter-advanced.yml b/.github/workflows/generate-linter-advanced.yml index cc673d52e..804edebdc 100644 --- a/.github/workflows/generate-linter-advanced.yml +++ b/.github/workflows/generate-linter-advanced.yml @@ -8,10 +8,11 @@ jobs: framework_matrix: strategy: matrix: - framework: [chi, gin, fiber, gorilla/mux, httprouter, standard-library, echo] + framework: + [chi, gin, fiber, gorilla/mux, httprouter, standard-library, echo] driver: [postgres] git: [commit] - advanced: [htmx, githubaction, websocket, tailwind, docker, react] + advanced: [htmx, githubaction, websocket, tailwind, docker, react, sqlc] runs-on: ubuntu-latest steps: @@ -20,7 +21,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '1.23.x' + go-version: "1.23.x" - name: Install golangci-lint run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.63.4 @@ -39,12 +40,18 @@ jobs: - if: ${{ matrix.advanced == 'htmx' || matrix.advanced == 'tailwind' }} name: Install Templ & gen templates - run: | + run: | go install github.com/a-h/templ/cmd/templ@latest - /home/runner/go/bin/templ generate -path ${{ env.PROJECT_DIRECTORY }} + $(go env GOPATH)/bin/templ generate -path ${{ env.PROJECT_DIRECTORY }} + + - if: ${{ matrix.advanced == 'sqlc'}} + name: Install Sqlc & gen code + run: | + go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest + $(go env GOPATH)/bin/sqlc generate -f ${{ env.PROJECT_DIRECTORY }}/sqlc.yaml - name: golangci-lint - run: | + run: | cd ${{ env.PROJECT_DIRECTORY }} golangci-lint run diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml new file mode 100644 index 000000000..93bffd5e7 --- /dev/null +++ b/.github/workflows/npm-publish.yml @@ -0,0 +1,63 @@ +name: npm-publish + +on: + workflow_call: + inputs: + tag: + description: "Release tag to publish (e.g., v1.0.0)" + required: true + type: string + workflow_dispatch: + inputs: + tag: + description: "Release tag to publish (e.g., v1.0.0)" + required: true + type: string + +jobs: + npm-publish: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + registry-url: "https://registry.npmjs.org" + + - name: Download release assets + run: | + TAG="${{ inputs.tag }}" + VERSION=${TAG#v} + mkdir -p dist + gh release download "$TAG" --dir dist + echo "VERSION=$VERSION" >> $GITHUB_ENV + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create npm packages + run: | + chmod +x ./scripts/create-npm-packages.sh + ./scripts/create-npm-packages.sh "$VERSION" + + - name: Publish platform-specific packages to npm + run: | + for platform_dir in platform-packages/go-blueprint-*; do + if [ -d "$platform_dir" ]; then + cd "$platform_dir" + npm publish --provenance --access public + cd - > /dev/null + fi + done + + - name: Publish main package to npm + run: | + cd npm-package + npm publish --provenance --access public + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 583ed0b20..c23c2fa21 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,9 +16,8 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.21.1' - - - name: Run GoReleaser + go-version: "1.21.1" + - name: Run GoReleaser uses: goreleaser/goreleaser-action@v5.0.0 with: distribution: goreleaser @@ -27,3 +26,14 @@ jobs: workdir: ./ env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + npm-publish: + needs: goreleaser + permissions: + contents: read + id-token: write + uses: ./.github/workflows/npm-publish.yml + with: + tag: ${{ github.ref_name }} + secrets: inherit + diff --git a/README.md b/README.md index f2ec319bc..c5ce0ccea 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ gives the option to integrate with one of the more popular Go frameworks (and th Install +### Go Install ```bash go install github.com/melkeydev/go-blueprint@latest ``` @@ -55,6 +56,16 @@ don't forget to update source ~/.zshrc ``` +### NPM Install +```bash +npm install -g @melkeydev/go-blueprint +``` + +### Homebrew Install +```bash +brew install go-blueprint +``` + Then in a new terminal run: ```bash @@ -126,6 +137,7 @@ You can now use the `--advanced` flag when running the `create` command to get a - [Tailwind](https://tailwindcss.com/) css framework - Docker configuration for go project - [React](https://react.dev/) frontend written in TypeScript, including an example fetch request to the backend +- [SQLC](https://sqlc.dev/) for generating type-safe Go code from SQL queries Note: Selecting Tailwind option will automatically select HTMX unless React is explicitly selected @@ -203,10 +215,17 @@ React: go-blueprint create --advanced --feature react ``` +SQLC: + +```bash +go-blueprint create --advanced --feature sqlc +``` + + Or all features at once: ```bash -go-blueprint create --name my-project --framework chi --driver mysql --advanced --feature htmx --feature githubaction --feature websocket --feature tailwind --feature docker --git commit --feature react +go-blueprint create --name my-project --framework chi --driver mysql --advanced --feature htmx --feature githubaction --feature websocket --feature tailwind --feature docker --git commit --feature react --feature sqlc ```

diff --git a/cmd/create.go b/cmd/create.go index 908e045ba..9419a78ef 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -18,6 +18,7 @@ import ( "github.com/melkeydev/go-blueprint/cmd/ui/textinput" "github.com/melkeydev/go-blueprint/cmd/utils" "github.com/spf13/cobra" + "slices" ) const logo = ` @@ -52,6 +53,11 @@ func init() { createCmd.Flags().BoolP("advanced", "a", false, "Get prompts for advanced features") createCmd.Flags().Var(&advancedFeatures, "feature", fmt.Sprintf("Advanced feature to use. Allowed values: %s", strings.Join(flags.AllowedAdvancedFeatures, ", "))) createCmd.Flags().VarP(&flagGit, "git", "g", fmt.Sprintf("Git to use. Allowed values: %s", strings.Join(flags.AllowedGitsOptions, ", "))) + + utils.RegisterStaticCompletions(createCmd, "framework", flags.AllowedProjectTypes) + utils.RegisterStaticCompletions(createCmd, "driver", flags.AllowedDBDrivers) + utils.RegisterStaticCompletions(createCmd, "feature", flags.AllowedAdvancedFeatures) + utils.RegisterStaticCompletions(createCmd, "git", flags.AllowedGitsOptions) } type Options struct { @@ -113,7 +119,7 @@ var createCmd = &cobra.Command{ GitOptions: flagGit, } - steps := steps.InitSteps(flagFramework, flagDBDriver) + optionSteps := steps.InitSteps(flagFramework, flagDBDriver) fmt.Printf("%s\n", logoStyle.Render(logo)) // Advanced option steps: @@ -155,7 +161,7 @@ var createCmd = &cobra.Command{ if project.ProjectType == "" { isInteractive = true - step := steps.Steps["framework"] + step := optionSteps.Steps["framework"] tprogram = tea.NewProgram(multiInput.InitialModelMulti(step.Options, options.ProjectType, step.Headers, project)) if _, err := tprogram.Run(); err != nil { cobra.CheckErr(textinput.CreateErrorInputModel(err).Err()) @@ -175,7 +181,7 @@ var createCmd = &cobra.Command{ if project.DBDriver == "" { isInteractive = true - step := steps.Steps["driver"] + step := optionSteps.Steps["driver"] tprogram = tea.NewProgram(multiInput.InitialModelMulti(step.Options, options.DBDriver, step.Headers, project)) if _, err := tprogram.Run(); err != nil { cobra.CheckErr(textinput.CreateErrorInputModel(err).Err()) @@ -202,7 +208,14 @@ var createCmd = &cobra.Command{ } } else { isInteractive = true - step := steps.Steps["advanced"] + step := optionSteps.Steps["advanced"] + sqlcSupportedDrivers := []flags.Database{flags.Postgres, flags.MySql, flags.Sqlite} + + if !slices.Contains(sqlcSupportedDrivers, project.DBDriver) { + step.Options = slices.DeleteFunc(step.Options, func(s steps.Item) bool { + return s.Flag == "Sqlc" + }) + } tprogram = tea.NewProgram((multiSelect.InitialModelMultiSelect(step.Options, options.Advanced, step.Headers, project))) if _, err := tprogram.Run(); err != nil { cobra.CheckErr(textinput.CreateErrorInputModel(err).Err()) @@ -224,7 +237,7 @@ var createCmd = &cobra.Command{ if project.GitOptions == "" { isInteractive = true - step := steps.Steps["git"] + step := optionSteps.Steps["git"] tprogram = tea.NewProgram(multiInput.InitialModelMulti(step.Options, options.Git, step.Headers, project)) if _, err := tprogram.Run(); err != nil { cobra.CheckErr(textinput.CreateErrorInputModel(err).Err()) diff --git a/cmd/flags/advancedFeatures.go b/cmd/flags/advancedFeatures.go index f97d629e3..333fa5ece 100644 --- a/cmd/flags/advancedFeatures.go +++ b/cmd/flags/advancedFeatures.go @@ -14,9 +14,10 @@ const ( Tailwind string = "tailwind" React string = "react" Docker string = "docker" + Sqlc string = "sqlc" ) -var AllowedAdvancedFeatures = []string{string(React), string(Htmx), string(GoProjectWorkflow), string(Websocket), string(Tailwind), string(Docker)} +var AllowedAdvancedFeatures = []string{string(React), string(Htmx), string(GoProjectWorkflow), string(Websocket), string(Tailwind), string(Docker), string(Sqlc)} func (f AdvancedFeatures) String() string { return strings.Join(f, ",") diff --git a/cmd/program/program.go b/cmd/program/program.go index 5537017d8..295f791e9 100644 --- a/cmd/program/program.go +++ b/cmd/program/program.go @@ -253,15 +253,17 @@ func (p *Project) CreateMainFile() error { } // Check if user.email is set. - emailSet, err := utils.CheckGitConfig("user.email") - if err != nil { - return err - } + if p.GitOptions.String() != flags.Skip { - if !emailSet && p.GitOptions.String() != flags.Skip { - fmt.Println("user.email is not set in git config.") - fmt.Println("Please set up git config before trying again.") - panic("\nGIT CONFIG ISSUE: user.email is not set in git config.\n") + emailSet, err := utils.CheckGitConfig("user.email") + if err != nil { + return err + } + if !emailSet { + fmt.Println("user.email is not set in git config.") + fmt.Println("Please set up git config before trying again.") + panic("\nGIT CONFIG ISSUE: user.email is not set in git config.\n") + } } p.ProjectName = strings.TrimSpace(p.ProjectName) @@ -283,7 +285,7 @@ func (p *Project) CreateMainFile() error { p.createFrameworkMap() // Create go.mod - err = utils.InitGoMod(p.ProjectName, projectPath) + err := utils.InitGoMod(p.ProjectName, projectPath) if err != nil { log.Printf("Could not initialize go.mod in new project %v\n", err) return err @@ -301,6 +303,9 @@ func (p *Project) CreateMainFile() error { // Install the correct package for the selected driver if p.DBDriver != "none" { p.createDBDriverMap() + if p.AdvancedOptions[string(flags.Sqlc)] && (p.DBDriver != flags.Postgres && p.DBDriver != flags.MySql && p.DBDriver != flags.Sqlite) { + p.AdvancedOptions[string(flags.Sqlc)] = false + } err = utils.GoGetPackage(projectPath, p.DBDriverMap[p.DBDriver].packageName) if err != nil { log.Println("Could not install go dependency for chosen driver") @@ -346,7 +351,6 @@ func (p *Project) CreateMainFile() error { // Install the godotenv package err = utils.GoGetPackage(projectPath, godotenvPackage) - if err != nil { log.Println("Could not install go dependency") @@ -456,6 +460,44 @@ func (p *Project) CreateMainFile() error { } } + if p.AdvancedOptions[string(flags.Sqlc)] { + yamlFile, err := os.Create(fmt.Sprintf("%s/sqlc.yaml", projectPath)) + if err != nil { + return err + } + defer yamlFile.Close() + + yamlTemplate := template.Must(template.New("sqlcyaml").Parse((string(advanced.SqlcYamlTemplate())))) + err = yamlTemplate.Execute(yamlFile, p) + if err != nil { + return err + } + + err = os.MkdirAll(fmt.Sprintf("%s/%s/sql", projectPath, internalDatabasePath), 0o755) + if err != nil { + return err + } + + schemaFile, err := os.Create(fmt.Sprintf("%s/%s/sql/schema.sql", projectPath, internalDatabasePath)) + if err != nil { + return err + } + defer schemaFile.Close() + + queryFile, err := os.Create(fmt.Sprintf("%s/%s/sql/query.sql", projectPath, internalDatabasePath)) + if err != nil { + return err + } + defer queryFile.Close() + + queryTemplate := advanced.SqlcQueryTemplate() + _, err = queryFile.Write(queryTemplate) + if err != nil { + return err + } + + } + if p.AdvancedOptions[string(flags.Htmx)] { // create folders and hello world file err = p.CreatePath(cmdWebPath, projectPath) @@ -504,6 +546,18 @@ func (p *Project) CreateMainFile() error { return err } + htmxTailwindConfigJsFile, err := os.Create(fmt.Sprintf("%s/tailwind.config.js", projectPath)) + if err != nil { + return err + } + defer htmxTailwindConfigJsFile.Close() + + htmxTailwindConfigJsTemplate := advanced.HtmxTailwindConfigJsTemplate() + err = os.WriteFile(fmt.Sprintf("%s/tailwind.config.js", projectPath), htmxTailwindConfigJsTemplate, 0o644) + if err != nil { + return err + } + efsFile, err := os.Create(fmt.Sprintf("%s/%s/efs.go", projectPath, cmdWebPath)) if err != nil { return err @@ -679,12 +733,12 @@ func (p *Project) CreateMainFile() error { return err } - nameSet, err := utils.CheckGitConfig("user.name") - if err != nil { - return err - } - if p.GitOptions != flags.Skip { + nameSet, err := utils.CheckGitConfig("user.name") + if err != nil { + return err + } + if !nameSet { fmt.Println("user.name is not set in git config.") fmt.Println("Please set up git config before trying again.") @@ -879,7 +933,7 @@ func (p *Project) CreateViteReactProject(projectPath string) error { cmd := exec.Command("npm", "install", "--prefer-offline", "--no-fund", - "tailwindcss", "@tailwindcss/vite") + "tailwindcss@^4", "@tailwindcss/vite") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { @@ -918,6 +972,7 @@ func (p *Project) CreateViteReactProject(projectPath string) error { return nil } + func (p *Project) CreateHtmxTemplates() { routesPlaceHolder := "" importsPlaceHolder := "" diff --git a/cmd/steps/steps.go b/cmd/steps/steps.go index eacb874bc..dd6d60e85 100644 --- a/cmd/steps/steps.go +++ b/cmd/steps/steps.go @@ -96,6 +96,11 @@ func InitSteps(projectType flags.Framework, databaseType flags.Database) *Steps StepName: "Advanced Features", Headers: "Which advanced features do you want?", Options: []Item{ + { + Flag: "Sqlc", + Title: "Sqlc", + Desc: "Generates fully type-safe idiomatic Go code from Postgres, MySql, and SQlite", + }, { Flag: "React", Title: "React", diff --git a/cmd/template/advanced/files/docker/dockerfile.tmpl b/cmd/template/advanced/files/docker/dockerfile.tmpl index 961b5a56d..5690f6171 100644 --- a/cmd/template/advanced/files/docker/dockerfile.tmpl +++ b/cmd/template/advanced/files/docker/dockerfile.tmpl @@ -1,6 +1,6 @@ -FROM golang:1.23-alpine AS build +FROM golang:1.24.4-alpine AS build {{- if or (.AdvancedOptions.tailwind) (eq .DBDriver "sqlite") }} -RUN apk add --no-cache{{- if .AdvancedOptions.tailwind }} curl{{ end }}{{- if (eq .DBDriver "sqlite") }} alpine-sdk{{ end }} +RUN apk add --no-cache{{- if .AdvancedOptions.tailwind }} curl libstdc++ libgcc{{ end }}{{- if (eq .DBDriver "sqlite") }} alpine-sdk{{ end }} {{- end }} WORKDIR /app @@ -16,7 +16,7 @@ RUN go install github.com/a-h/templ/cmd/templ@latest && \ {{- end}} {{- if .AdvancedOptions.tailwind}} - curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss && \ + curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64-musl -o tailwindcss && \ chmod +x tailwindcss && \ ./tailwindcss -i cmd/web/styles/input.css -o cmd/web/assets/css/output.css {{- end }} diff --git a/cmd/template/advanced/files/htmx/htmx.min.js.tmpl b/cmd/template/advanced/files/htmx/htmx.min.js.tmpl index e29aba6b0..39250e01b 100644 --- a/cmd/template/advanced/files/htmx/htmx.min.js.tmpl +++ b/cmd/template/advanced/files/htmx/htmx.min.js.tmpl @@ -11,7 +11,7 @@ var htmx = (function () { findAll: null, closest: null, values: function (e, t) { - const n = cn(e, t || "post"); + const n = dn(e, t || "post"); return n.values; }, remove: null, @@ -64,18 +64,20 @@ var htmx = (function () { { code: "[45]..", swap: false, error: true }, ], allowNestedOobSwaps: true, + historyRestoreAsHxRequest: true, }, parseInterval: null, + location: location, _: null, - version: "2.0.4", + version: "2.0.6", }; Q.onLoad = j; - Q.process = kt; - Q.on = ye; + Q.process = Ft; + Q.on = xe; Q.off = be; - Q.trigger = he; - Q.ajax = Rn; - Q.find = u; + Q.trigger = ae; + Q.ajax = Ln; + Q.find = f; Q.findAll = x; Q.closest = g; Q.remove = z; @@ -84,43 +86,43 @@ var htmx = (function () { Q.toggleClass = W; Q.takeClass = Z; Q.swap = $e; - Q.defineExtension = Fn; - Q.removeExtension = Bn; + Q.defineExtension = zn; + Q.removeExtension = $n; Q.logAll = V; Q.logNone = _; Q.parseInterval = d; Q._ = e; const n = { addTriggerHandler: St, - bodyContains: le, + bodyContains: se, canAccessLocalStorage: B, findThisElement: Se, - filterValues: hn, + filterValues: yn, swap: $e, hasAttribute: s, - getAttributeValue: te, - getClosestAttributeValue: re, - getClosestMatch: o, - getExpressionVars: En, - getHeaders: fn, - getInputValues: cn, - getInternalData: ie, - getSwapSpecification: gn, + getAttributeValue: a, + getClosestAttributeValue: ne, + getClosestMatch: q, + getExpressionVars: Tn, + getHeaders: mn, + getInputValues: dn, + getInternalData: oe, + getSwapSpecification: bn, getTriggerSpecs: st, getTarget: Ee, makeFragment: P, - mergeObjects: ce, - makeSettleInfo: xn, + mergeObjects: le, + makeSettleInfo: Sn, oobSwap: He, - querySelectorExt: ae, - settleImmediately: Kt, + querySelectorExt: ue, + settleImmediately: Yt, shouldCancel: ht, - triggerEvent: he, + triggerEvent: ae, triggerErrorEvent: fe, - withExtensions: Ft, + withExtensions: jt, }; - const r = ["get", "post", "put", "delete", "patch"]; - const H = r + const de = ["get", "post", "put", "delete", "patch"]; + const T = de .map(function (e) { return "[hx-" + e + "], [data-hx-" + e + "]"; }) @@ -149,30 +151,30 @@ var htmx = (function () { !!e.hasAttribute && (e.hasAttribute(t) || e.hasAttribute("data-" + t)) ); } - function te(e, t) { + function a(e, t) { return ee(e, t) || ee(e, "data-" + t); } - function c(e) { + function u(e) { const t = e.parentElement; if (!t && e.parentNode instanceof ShadowRoot) return e.parentNode; return t; } - function ne() { + function te() { return document; } - function m(e, t) { - return e.getRootNode ? e.getRootNode({ composed: t }) : ne(); + function y(e, t) { + return e.getRootNode ? e.getRootNode({ composed: t }) : te(); } - function o(e, t) { + function q(e, t) { while (e && !t(e)) { - e = c(e); + e = u(e); } return e || null; } - function i(e, t, n) { - const r = te(t, n); - const o = te(t, "hx-disinherit"); - var i = te(t, "hx-inherit"); + function o(e, t, n) { + const r = a(t, n); + const o = a(t, "hx-disinherit"); + var i = a(t, "hx-inherit"); if (e !== t) { if (Q.config.disableInheritance) { if (i && (i === "*" || i.split(" ").indexOf(n) >= 0)) { @@ -187,27 +189,19 @@ var htmx = (function () { } return r; } - function re(t, n) { + function ne(t, n) { let r = null; - o(t, function (e) { - return !!(r = i(t, ue(e), n)); + q(t, function (e) { + return !!(r = o(t, ce(e), n)); }); if (r !== "unset") { return r; } } function h(e, t) { - const n = - e instanceof Element && - (e.matches || - e.matchesSelector || - e.msMatchesSelector || - e.mozMatchesSelector || - e.webkitMatchesSelector || - e.oMatchesSelector); - return !!n && n.call(e, t); - } - function T(e) { + return e instanceof Element && e.matches(t); + } + function A(e) { const t = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i; const n = t.exec(e); if (n) { @@ -216,18 +210,18 @@ var htmx = (function () { return ""; } } - function q(e) { + function L(e) { const t = new DOMParser(); return t.parseFromString(e, "text/html"); } - function L(e, t) { + function N(e, t) { while (t.childNodes.length > 0) { e.append(t.childNodes[0]); } } - function A(e) { - const t = ne().createElement("script"); - se(e.attributes, function (e) { + function r(e) { + const t = te().createElement("script"); + ie(e.attributes, function (e) { t.setAttribute(e.name, e.value); }); t.textContent = e.textContent; @@ -237,7 +231,7 @@ var htmx = (function () { } return t; } - function N(e) { + function i(e) { return ( e.matches("script") && (e.type === "text/javascript" || e.type === "module" || e.type === "") @@ -245,13 +239,13 @@ var htmx = (function () { } function I(e) { Array.from(e.querySelectorAll("script")).forEach((e) => { - if (N(e)) { - const t = A(e); + if (i(e)) { + const t = r(e); const n = e.parentNode; try { n.insertBefore(t, e); } catch (e) { - O(e); + R(e); } finally { e.remove(); } @@ -260,20 +254,20 @@ var htmx = (function () { } function P(e) { const t = e.replace(/]*)?>[\s\S]*?<\/head>/i, ""); - const n = T(t); + const n = A(t); let r; if (n === "html") { r = new DocumentFragment(); - const i = q(e); - L(r, i.body); + const i = L(e); + N(r, i.body); r.title = i.title; } else if (n === "body") { r = new DocumentFragment(); - const i = q(t); - L(r, i.body); + const i = L(t); + N(r, i.body); r.title = i.title; } else { - const i = q( + const i = L( '", @@ -295,7 +289,7 @@ var htmx = (function () { } return r; } - function oe(e) { + function re(e) { if (e) { e(); } @@ -303,13 +297,13 @@ var htmx = (function () { function t(e, t) { return Object.prototype.toString.call(e) === "[object " + t + "]"; } - function k(e) { + function D(e) { return typeof e === "function"; } - function D(e) { + function k(e) { return t(e, "Object"); } - function ie(e) { + function oe(e) { const t = "htmx-internal-data"; let n = e[t]; if (!n) { @@ -326,26 +320,26 @@ var htmx = (function () { } return n; } - function se(t, n) { + function ie(t, n) { if (t) { for (let e = 0; e < t.length; e++) { n(t[e]); } } } - function X(e) { + function F(e) { const t = e.getBoundingClientRect(); const n = t.top; const r = t.bottom; return n < window.innerHeight && r >= 0; } - function le(e) { + function se(e) { return e.getRootNode({ composed: true }) === document; } - function F(e) { + function X(e) { return e.trim().split(/\s+/); } - function ce(e, t) { + function le(e, t) { for (const n in t) { if (t.hasOwnProperty(n)) { e[n] = t[n]; @@ -353,40 +347,36 @@ var htmx = (function () { } return e; } - function S(e) { + function v(e) { try { return JSON.parse(e); } catch (e) { - O(e); + R(e); return null; } } function B() { - const e = "htmx:localStorageTest"; + const e = "htmx:sessionStorageTest"; try { - localStorage.setItem(e, e); - localStorage.removeItem(e); + sessionStorage.setItem(e, e); + sessionStorage.removeItem(e); return true; } catch (e) { return false; } } - function U(t) { - try { - const e = new URL(t); - if (e) { - t = e.pathname + e.search; - } - if (!/^\/$/.test(t)) { - t = t.replace(/\/+$/, ""); - } - return t; - } catch (e) { - return t; + function U(e) { + const t = new URL(e, "http://x"); + if (t) { + e = t.pathname + t.search; } + if (e != "/") { + e = e.replace(/\/+$/, ""); + } + return e; } function e(e) { - return vn(ne().body, function () { + return On(te().body, function () { return eval(e); }); } @@ -406,35 +396,35 @@ var htmx = (function () { function _() { Q.logger = null; } - function u(e, t) { + function f(e, t) { if (typeof e !== "string") { return e.querySelector(t); } else { - return u(ne(), e); + return f(te(), e); } } function x(e, t) { if (typeof e !== "string") { return e.querySelectorAll(t); } else { - return x(ne(), e); + return x(te(), e); } } - function E() { + function b() { return window; } function z(e, t) { - e = y(e); + e = w(e); if (t) { - E().setTimeout(function () { + b().setTimeout(function () { z(e); e = null; }, t); } else { - c(e).removeChild(e); + u(e).removeChild(e); } } - function ue(e) { + function ce(e) { return e instanceof Element ? e : null; } function $(e) { @@ -443,7 +433,7 @@ var htmx = (function () { function J(e) { return typeof e === "string" ? e : null; } - function f(e) { + function p(e) { return e instanceof Element || e instanceof Document || e instanceof DocumentFragment @@ -451,12 +441,12 @@ var htmx = (function () { : null; } function K(e, t, n) { - e = ue(y(e)); + e = ce(w(e)); if (!e) { return; } if (n) { - E().setTimeout(function () { + b().setTimeout(function () { K(e, t); e = null; }, n); @@ -465,12 +455,12 @@ var htmx = (function () { } } function G(e, t, n) { - let r = ue(y(e)); + let r = ce(w(e)); if (!r) { return; } if (n) { - E().setTimeout(function () { + b().setTimeout(function () { G(r, t); r = null; }, n); @@ -484,28 +474,22 @@ var htmx = (function () { } } function W(e, t) { - e = y(e); + e = w(e); e.classList.toggle(t); } function Z(e, t) { - e = y(e); - se(e.parentElement.children, function (e) { + e = w(e); + ie(e.parentElement.children, function (e) { G(e, t); }); - K(ue(e), t); + K(ce(e), t); } function g(e, t) { - e = ue(y(e)); - if (e && e.closest) { + e = ce(w(e)); + if (e) { return e.closest(t); - } else { - do { - if (e == null || h(e, t)) { - return e; - } - } while ((e = e && ue(c(e)))); - return null; } + return null; } function l(e, t) { return e.substring(0, t.length) === t; @@ -513,7 +497,7 @@ var htmx = (function () { function Y(e, t) { return e.substring(e.length - t.length) === t; } - function ge(e) { + function pe(e) { const t = e.trim(); if (l(t, "<") && Y(t, "/>")) { return t.substring(1, t.length - 2); @@ -521,11 +505,11 @@ var htmx = (function () { return t; } } - function p(t, r, n) { + function m(t, r, n) { if (r.indexOf("global ") === 0) { - return p(t, r.slice(7), true); + return m(t, r.slice(7), true); } - t = y(t); + t = w(t); const o = []; { let t = 0; @@ -550,20 +534,20 @@ var htmx = (function () { const i = []; const s = []; while (o.length > 0) { - const r = ge(o.shift()); + const r = pe(o.shift()); let e; if (r.indexOf("closest ") === 0) { - e = g(ue(t), ge(r.substr(8))); + e = g(ce(t), pe(r.slice(8))); } else if (r.indexOf("find ") === 0) { - e = u(f(t), ge(r.substr(5))); + e = f(p(t), pe(r.slice(5))); } else if (r === "next" || r === "nextElementSibling") { - e = ue(t).nextElementSibling; + e = ce(t).nextElementSibling; } else if (r.indexOf("next ") === 0) { - e = pe(t, ge(r.substr(5)), !!n); + e = ge(t, pe(r.slice(5)), !!n); } else if (r === "previous" || r === "previousElementSibling") { - e = ue(t).previousElementSibling; + e = ce(t).previousElementSibling; } else if (r.indexOf("previous ") === 0) { - e = me(t, ge(r.substr(9)), !!n); + e = me(t, pe(r.slice(9)), !!n); } else if (r === "document") { e = document; } else if (r === "window") { @@ -571,7 +555,7 @@ var htmx = (function () { } else if (r === "body") { e = document.body; } else if (r === "root") { - e = m(t, !!n); + e = y(t, !!n); } else if (r === "host") { e = t.getRootNode().host; } else { @@ -583,13 +567,13 @@ var htmx = (function () { } if (s.length > 0) { const e = s.join(","); - const c = f(m(t, !!n)); + const c = p(y(t, !!n)); i.push(...M(c.querySelectorAll(e))); } return i; } - var pe = function (t, e, n) { - const r = f(m(t, n)).querySelectorAll(e); + var ge = function (t, e, n) { + const r = p(y(t, n)).querySelectorAll(e); for (let e = 0; e < r.length; e++) { const o = r[e]; if (o.compareDocumentPosition(t) === Node.DOCUMENT_POSITION_PRECEDING) { @@ -598,7 +582,7 @@ var htmx = (function () { } }; var me = function (t, e, n) { - const r = f(m(t, n)).querySelectorAll(e); + const r = p(y(t, n)).querySelectorAll(e); for (let e = r.length - 1; e >= 0; e--) { const o = r[e]; if (o.compareDocumentPosition(t) === Node.DOCUMENT_POSITION_FOLLOWING) { @@ -606,52 +590,63 @@ var htmx = (function () { } } }; - function ae(e, t) { + function ue(e, t) { if (typeof e !== "string") { - return p(e, t)[0]; + return m(e, t)[0]; } else { - return p(ne().body, e)[0]; + return m(te().body, e)[0]; } } - function y(e, t) { + function w(e, t) { if (typeof e === "string") { - return u(f(t) || document, e); + return f(p(t) || document, e); } else { return e; } } - function xe(e, t, n, r) { - if (k(t)) { - return { target: ne().body, event: J(e), listener: t, options: n }; + function ye(e, t, n, r) { + if (D(t)) { + return { target: te().body, event: J(e), listener: t, options: n }; } else { - return { target: y(e), event: J(t), listener: n, options: r }; + return { target: w(e), event: J(t), listener: n, options: r }; } } - function ye(t, n, r, o) { - Vn(function () { - const e = xe(t, n, r, o); + function xe(t, n, r, o) { + Gn(function () { + const e = ye(t, n, r, o); e.target.addEventListener(e.event, e.listener, e.options); }); - const e = k(n); + const e = D(n); return e ? n : r; } function be(t, n, r) { - Vn(function () { - const e = xe(t, n, r); + Gn(function () { + const e = ye(t, n, r); e.target.removeEventListener(e.event, e.listener); }); - return k(n) ? n : r; + return D(n) ? n : r; } - const ve = ne().createElement("output"); - function we(e, t) { - const n = re(e, t); - if (n) { - if (n === "this") { - return [Se(e, t)]; + const ve = te().createElement("output"); + function we(t, n) { + const e = ne(t, n); + if (e) { + if (e === "this") { + return [Se(t, n)]; } else { - const r = p(e, n); + const r = m(t, e); + const o = /(^|,)(\s*)inherit(\s*)($|,)/.test(e); + if (o) { + const i = ce( + q(t, function (e) { + return e !== t && s(ce(e), n); + }), + ); + if (i) { + r.push(...we(i, n)); + } + } if (r.length === 0) { - O('The selector "' + n + '" on ' + t + " returned no matches!"); + R('The selector "' + e + '" on ' + n + " returned no matches!"); return [ve]; } else { return r; @@ -660,52 +655,46 @@ var htmx = (function () { } } function Se(e, t) { - return ue( - o(e, function (e) { - return te(ue(e), t) != null; + return ce( + q(e, function (e) { + return a(ce(e), t) != null; }), ); } function Ee(e) { - const t = re(e, "hx-target"); + const t = ne(e, "hx-target"); if (t) { if (t === "this") { return Se(e, "hx-target"); } else { - return ae(e, t); + return ue(e, t); } } else { - const n = ie(e); + const n = oe(e); if (n.boosted) { - return ne().body; + return te().body; } else { return e; } } } - function Ce(t) { - const n = Q.config.attributesToSettle; - for (let e = 0; e < n.length; e++) { - if (t === n[e]) { - return true; - } - } - return false; + function Ce(e) { + return Q.config.attributesToSettle.includes(e); } function Oe(t, n) { - se(t.attributes, function (e) { + ie(t.attributes, function (e) { if (!n.hasAttribute(e.name) && Ce(e.name)) { t.removeAttribute(e.name); } }); - se(n.attributes, function (e) { + ie(n.attributes, function (e) { if (Ce(e.name)) { t.setAttribute(e.name, e.value); } }); } function Re(t, e) { - const n = Un(e); + const n = Jn(e); for (let e = 0; e < n.length; e++) { const r = n[e]; try { @@ -713,14 +702,14 @@ var htmx = (function () { return true; } } catch (e) { - O(e); + R(e); } } return t === "outerHTML"; } function He(e, o, i, t) { - t = t || ne(); - let n = "#" + ee(o, "id"); + t = t || te(); + let n = "#" + CSS.escape(ee(o, "id")); let s = "outerHTML"; if (e === "true") { } else if (e.indexOf(":") > 0) { @@ -731,40 +720,40 @@ var htmx = (function () { } o.removeAttribute("hx-swap-oob"); o.removeAttribute("data-hx-swap-oob"); - const r = p(t, n, false); - if (r) { - se(r, function (e) { + const r = m(t, n, false); + if (r.length) { + ie(r, function (e) { let t; const n = o.cloneNode(true); - t = ne().createDocumentFragment(); + t = te().createDocumentFragment(); t.appendChild(n); if (!Re(s, e)) { - t = f(n); + t = p(n); } const r = { shouldSwap: true, target: e, fragment: t }; - if (!he(e, "htmx:oobBeforeSwap", r)) return; + if (!ae(e, "htmx:oobBeforeSwap", r)) return; e = r.target; if (r.shouldSwap) { qe(t); _e(s, e, e, t, i); Te(); } - se(i.elts, function (e) { - he(e, "htmx:oobAfterSwap", r); + ie(i.elts, function (e) { + ae(e, "htmx:oobAfterSwap", r); }); }); o.parentNode.removeChild(o); } else { o.parentNode.removeChild(o); - fe(ne().body, "htmx:oobErrorNoTarget", { content: o }); + fe(te().body, "htmx:oobErrorNoTarget", { content: o }); } return e; } function Te() { - const e = u("#--htmx-preserve-pantry--"); + const e = f("#--htmx-preserve-pantry--"); if (e) { for (const t of [...e.children]) { - const n = u("#" + t.id); + const n = f("#" + t.id); n.parentNode.moveBefore(t, n); n.remove(); } @@ -772,18 +761,18 @@ var htmx = (function () { } } function qe(e) { - se(x(e, "[hx-preserve], [data-hx-preserve]"), function (e) { - const t = te(e, "id"); - const n = ne().getElementById(t); + ie(x(e, "[hx-preserve], [data-hx-preserve]"), function (e) { + const t = a(e, "id"); + const n = te().getElementById(t); if (n != null) { if (e.moveBefore) { - let e = u("#--htmx-preserve-pantry--"); + let e = f("#--htmx-preserve-pantry--"); if (e == null) { - ne().body.insertAdjacentHTML( + te().body.insertAdjacentHTML( "afterend", "

", ); - e = u("#--htmx-preserve-pantry--"); + e = f("#--htmx-preserve-pantry--"); } e.moveBefore(n, null); } else { @@ -792,13 +781,13 @@ var htmx = (function () { } }); } - function Le(l, e, c) { - se(e.querySelectorAll("[id]"), function (t) { + function Ae(l, e, c) { + ie(e.querySelectorAll("[id]"), function (t) { const n = ee(t, "id"); if (n && n.length > 0) { const r = n.replace("'", "\\'"); const o = t.tagName.replace(":", "\\:"); - const e = f(l); + const e = p(l); const i = e && e.querySelector(o + "[id='" + r + "']"); if (i && i !== e) { const s = t.cloneNode(); @@ -810,12 +799,12 @@ var htmx = (function () { } }); } - function Ae(e) { + function Le(e) { return function () { G(e, Q.config.addedClass); - kt(ue(e)); - Ne(f(e)); - he(e, "htmx:load"); + Ft(ce(e)); + Ne(p(e)); + ae(e, "htmx:load"); }; } function Ne(e) { @@ -825,14 +814,14 @@ var htmx = (function () { n.focus(); } } - function a(e, t, n, r) { - Le(e, n, r); + function c(e, t, n, r) { + Ae(e, n, r); while (n.childNodes.length > 0) { const o = n.firstChild; - K(ue(o), Q.config.addedClass); + K(ce(o), Q.config.addedClass); e.insertBefore(o, t); if (o.nodeType !== Node.TEXT_NODE && o.nodeType !== Node.COMMENT_NODE) { - r.tasks.push(Ae(o)); + r.tasks.push(Le(o)); } } } @@ -845,19 +834,17 @@ var htmx = (function () { } function Pe(t) { let n = 0; - if (t.attributes) { - for (let e = 0; e < t.attributes.length; e++) { - const r = t.attributes[e]; - if (r.value) { - n = Ie(r.name, n); - n = Ie(r.value, n); - } + for (let e = 0; e < t.attributes.length; e++) { + const r = t.attributes[e]; + if (r.value) { + n = Ie(r.name, n); + n = Ie(r.value, n); } } return n; } - function ke(t) { - const n = ie(t); + function De(t) { + const n = oe(t); if (n.onHandlers) { for (let e = 0; e < n.onHandlers.length; e++) { const r = n.onHandlers[e]; @@ -866,43 +853,41 @@ var htmx = (function () { delete n.onHandlers; } } - function De(e) { - const t = ie(e); + function ke(e) { + const t = oe(e); if (t.timeout) { clearTimeout(t.timeout); } if (t.listenerInfos) { - se(t.listenerInfos, function (e) { + ie(t.listenerInfos, function (e) { if (e.on) { be(e.on, e.trigger, e.listener); } }); } - ke(e); - se(Object.keys(t), function (e) { + De(e); + ie(Object.keys(t), function (e) { if (e !== "firstInitCompleted") delete t[e]; }); } - function b(e) { - he(e, "htmx:beforeCleanupElement"); - De(e); - if (e.children) { - se(e.children, function (e) { - b(e); - }); - } + function S(e) { + ae(e, "htmx:beforeCleanupElement"); + ke(e); + ie(e.children, function (e) { + S(e); + }); } function Me(t, e, n) { - if (t instanceof Element && t.tagName === "BODY") { + if (t.tagName === "BODY") { return Ve(t, e, n); } let r; const o = t.previousSibling; - const i = c(t); + const i = u(t); if (!i) { return; } - a(i, t, e, n); + c(i, t, e, n); if (o == null) { r = i.firstChild; } else { @@ -917,41 +902,37 @@ var htmx = (function () { } r = r.nextSibling; } - b(t); - if (t instanceof Element) { - t.remove(); - } else { - t.parentNode.removeChild(t); - } - } - function Xe(e, t, n) { - return a(e, e.firstChild, t, n); + S(t); + t.remove(); } function Fe(e, t, n) { - return a(c(e), e, t, n); + return c(e, e.firstChild, t, n); + } + function Xe(e, t, n) { + return c(u(e), e, t, n); } function Be(e, t, n) { - return a(e, null, t, n); + return c(e, null, t, n); } function Ue(e, t, n) { - return a(c(e), e.nextSibling, t, n); + return c(u(e), e.nextSibling, t, n); } function je(e) { - b(e); - const t = c(e); + S(e); + const t = u(e); if (t) { return t.removeChild(e); } } function Ve(e, t, n) { const r = e.firstChild; - a(e, r, t, n); + c(e, r, t, n); if (r) { while (r.nextSibling) { - b(r.nextSibling); + S(r.nextSibling); e.removeChild(r.nextSibling); } - b(r); + S(r); e.removeChild(r); } } @@ -963,10 +944,10 @@ var htmx = (function () { Me(n, r, o); return; case "afterbegin": - Xe(n, r, o); + Fe(n, r, o); return; case "beforebegin": - Fe(n, r, o); + Xe(n, r, o); return; case "beforeend": Be(n, r, o); @@ -978,7 +959,7 @@ var htmx = (function () { je(n); return; default: - var i = Un(e); + var i = Jn(e); for (let e = 0; e < i.length; e++) { const s = i[e]; try { @@ -991,14 +972,14 @@ var htmx = (function () { c.nodeType !== Node.TEXT_NODE && c.nodeType !== Node.COMMENT_NODE ) { - o.tasks.push(Ae(c)); + o.tasks.push(Le(c)); } } } return; } } catch (e) { - O(e); + R(e); } } if (t === "innerHTML") { @@ -1010,9 +991,9 @@ var htmx = (function () { } function ze(e, n, r) { var t = x(e, "[hx-swap-oob], [data-hx-swap-oob]"); - se(t, function (e) { + ie(t, function (e) { if (Q.config.allowNestedOobSwaps || e.parentElement === null) { - const t = te(e, "hx-swap-oob"); + const t = a(e, "hx-swap-oob"); if (t != null) { He(t, e, n, r); } @@ -1023,144 +1004,181 @@ var htmx = (function () { }); return t.length > 0; } - function $e(e, t, r, o) { - if (!o) { - o = {}; - } - e = y(e); - const i = o.contextElement ? m(o.contextElement, false) : ne(); - const n = document.activeElement; - let s = {}; - try { - s = { - elt: n, - start: n ? n.selectionStart : null, - end: n ? n.selectionEnd : null, + function $e(h, d, p, g) { + if (!g) { + g = {}; + } + let m = null; + let n = null; + let e = function () { + re(g.beforeSwapCallback); + h = w(h); + const r = g.contextElement ? y(g.contextElement, false) : te(); + const e = document.activeElement; + let t = {}; + t = { + elt: e, + start: e ? e.selectionStart : null, + end: e ? e.selectionEnd : null, }; - } catch (e) {} - const l = xn(e); - if (r.swapStyle === "textContent") { - e.textContent = t; - } else { - let n = P(t); - l.title = n.title; - if (o.selectOOB) { - const u = o.selectOOB.split(","); - for (let t = 0; t < u.length; t++) { - const a = u[t].split(":", 2); - let e = a[0].trim(); - if (e.indexOf("#") === 0) { - e = e.substring(1); - } - const f = a[1] || "true"; - const h = n.querySelector("#" + e); - if (h) { - He(f, h, l, i); + const o = Sn(h); + if (p.swapStyle === "textContent") { + h.textContent = d; + } else { + let n = P(d); + o.title = g.title || n.title; + if (g.historyRequest) { + n = n.querySelector("[hx-history-elt],[data-hx-history-elt]") || n; + } + if (g.selectOOB) { + const i = g.selectOOB.split(","); + for (let t = 0; t < i.length; t++) { + const s = i[t].split(":", 2); + let e = s[0].trim(); + if (e.indexOf("#") === 0) { + e = e.substring(1); + } + const l = s[1] || "true"; + const c = n.querySelector("#" + e); + if (c) { + He(l, c, o, r); + } } } - } - ze(n, l, i); - se(x(n, "template"), function (e) { - if (e.content && ze(e.content, l, i)) { - e.remove(); - } - }); - if (o.select) { - const d = ne().createDocumentFragment(); - se(n.querySelectorAll(o.select), function (e) { - d.appendChild(e); + ze(n, o, r); + ie(x(n, "template"), function (e) { + if (e.content && ze(e.content, o, r)) { + e.remove(); + } }); - n = d; - } - qe(n); - _e(r.swapStyle, o.contextElement, e, n, l); - Te(); - } - if (s.elt && !le(s.elt) && ee(s.elt, "id")) { - const g = document.getElementById(ee(s.elt, "id")); - const p = { - preventScroll: - r.focusScroll !== undefined - ? !r.focusScroll - : !Q.config.defaultFocusScroll, - }; - if (g) { - if (s.start && g.setSelectionRange) { - try { - g.setSelectionRange(s.start, s.end); - } catch (e) {} + if (g.select) { + const u = te().createDocumentFragment(); + ie(n.querySelectorAll(g.select), function (e) { + u.appendChild(e); + }); + n = u; } - g.focus(p); + qe(n); + _e(p.swapStyle, g.contextElement, h, n, o); + Te(); } - } - e.classList.remove(Q.config.swappingClass); - se(l.elts, function (e) { - if (e.classList) { - e.classList.add(Q.config.settlingClass); + if (t.elt && !se(t.elt) && ee(t.elt, "id")) { + const f = document.getElementById(ee(t.elt, "id")); + const a = { + preventScroll: + p.focusScroll !== undefined + ? !p.focusScroll + : !Q.config.defaultFocusScroll, + }; + if (f) { + if (t.start && f.setSelectionRange) { + try { + f.setSelectionRange(t.start, t.end); + } catch (e) {} + } + f.focus(a); + } } - he(e, "htmx:afterSwap", o.eventInfo); - }); - if (o.afterSwapCallback) { - o.afterSwapCallback(); - } - if (!r.ignoreTitle) { - kn(l.title); - } - const c = function () { - se(l.tasks, function (e) { - e.call(); - }); - se(l.elts, function (e) { + h.classList.remove(Q.config.swappingClass); + ie(o.elts, function (e) { if (e.classList) { - e.classList.remove(Q.config.settlingClass); + e.classList.add(Q.config.settlingClass); } - he(e, "htmx:afterSettle", o.eventInfo); + ae(e, "htmx:afterSwap", g.eventInfo); }); - if (o.anchor) { - const e = ue(y("#" + o.anchor)); - if (e) { - e.scrollIntoView({ block: "start", behavior: "auto" }); - } + re(g.afterSwapCallback); + if (!p.ignoreTitle) { + Bn(o.title); } - yn(l.elts, r); - if (o.afterSettleCallback) { - o.afterSettleCallback(); + const n = function () { + ie(o.tasks, function (e) { + e.call(); + }); + ie(o.elts, function (e) { + if (e.classList) { + e.classList.remove(Q.config.settlingClass); + } + ae(e, "htmx:afterSettle", g.eventInfo); + }); + if (g.anchor) { + const e = ce(w("#" + g.anchor)); + if (e) { + e.scrollIntoView({ block: "start", behavior: "auto" }); + } + } + En(o.elts, p); + re(g.afterSettleCallback); + re(m); + }; + if (p.settleDelay > 0) { + b().setTimeout(n, p.settleDelay); + } else { + n(); } }; - if (r.settleDelay > 0) { - E().setTimeout(c, r.settleDelay); - } else { - c(); + let t = Q.config.globalViewTransitions; + if (p.hasOwnProperty("transition")) { + t = p.transition; + } + const r = g.contextElement || te(); + if ( + t && + ae(r, "htmx:beforeTransition", g.eventInfo) && + typeof Promise !== "undefined" && + document.startViewTransition + ) { + const o = new Promise(function (e, t) { + m = e; + n = t; + }); + const i = e; + e = function () { + document.startViewTransition(function () { + i(); + return o; + }); + }; + } + try { + if (p?.swapDelay && p.swapDelay > 0) { + b().setTimeout(e, p.swapDelay); + } else { + e(); + } + } catch (e) { + fe(r, "htmx:swapError", g.eventInfo); + re(n); + throw e; } } function Je(e, t, n) { const r = e.getResponseHeader(t); if (r.indexOf("{") === 0) { - const o = S(r); + const o = v(r); for (const i in o) { if (o.hasOwnProperty(i)) { let e = o[i]; - if (D(e)) { + if (k(e)) { n = e.target !== undefined ? e.target : n; } else { e = { value: e }; } - he(n, i, e); + ae(n, i, e); } } } else { const s = r.split(","); for (let e = 0; e < s.length; e++) { - he(n, s[e].trim(), []); + ae(n, s[e].trim(), []); } } } const Ke = /\s/; - const v = /[\s,]/; + const E = /[\s,]/; const Ge = /[_$a-zA-Z]/; const We = /[_$a-zA-Z0-9]/; const Ze = ['"', "'", "/"]; - const w = /[^\s]/; + const C = /[^\s]/; const Ye = /[{(]/; const Qe = /[})]/; function et(e) { @@ -1219,7 +1237,7 @@ var htmx = (function () { o.shift(); t += ")})"; try { - const l = vn( + const l = On( r, function () { return Function(t)(); @@ -1231,7 +1249,7 @@ var htmx = (function () { l.source = t; return l; } catch (e) { - fe(ne().body, "htmx:syntax:error", { error: e, source: t }); + fe(te().body, "htmx:syntax:error", { error: e, source: t }); return null; } } @@ -1258,7 +1276,7 @@ var htmx = (function () { } } } - function C(e, t) { + function O(e, t) { let n = ""; while (e.length > 0 && !t.test(e[0])) { n += e.shift(); @@ -1269,10 +1287,10 @@ var htmx = (function () { let t; if (e.length > 0 && Ye.test(e[0])) { e.shift(); - t = C(e, Qe).trim(); + t = O(e, Qe).trim(); e.shift(); } else { - t = C(e, v); + t = O(e, E); } return t; } @@ -1281,44 +1299,44 @@ var htmx = (function () { const r = []; const o = et(t); do { - C(o, w); + O(o, C); const l = o.length; - const c = C(o, /[,\[\s]/); + const c = O(o, /[,\[\s]/); if (c !== "") { if (c === "every") { const u = { trigger: "every" }; - C(o, w); - u.pollInterval = d(C(o, /[,\[\s]/)); - C(o, w); + O(o, C); + u.pollInterval = d(O(o, /[,\[\s]/)); + O(o, C); var i = nt(e, o, "event"); if (i) { u.eventFilter = i; } r.push(u); } else { - const a = { trigger: c }; + const f = { trigger: c }; var i = nt(e, o, "event"); if (i) { - a.eventFilter = i; + f.eventFilter = i; } - C(o, w); + O(o, C); while (o.length > 0 && o[0] !== ",") { - const f = o.shift(); - if (f === "changed") { - a.changed = true; - } else if (f === "once") { - a.once = true; - } else if (f === "consume") { - a.consume = true; - } else if (f === "delay" && o[0] === ":") { + const a = o.shift(); + if (a === "changed") { + f.changed = true; + } else if (a === "once") { + f.once = true; + } else if (a === "consume") { + f.consume = true; + } else if (a === "delay" && o[0] === ":") { o.shift(); - a.delay = d(C(o, v)); - } else if (f === "from" && o[0] === ":") { + f.delay = d(O(o, E)); + } else if (a === "from" && o[0] === ":") { o.shift(); if (Ye.test(o[0])) { var s = rt(o); } else { - var s = C(o, v); + var s = O(o, E); if ( s === "closest" || s === "find" || @@ -1332,34 +1350,34 @@ var htmx = (function () { } } } - a.from = s; - } else if (f === "target" && o[0] === ":") { + f.from = s; + } else if (a === "target" && o[0] === ":") { o.shift(); - a.target = rt(o); - } else if (f === "throttle" && o[0] === ":") { + f.target = rt(o); + } else if (a === "throttle" && o[0] === ":") { o.shift(); - a.throttle = d(C(o, v)); - } else if (f === "queue" && o[0] === ":") { + f.throttle = d(O(o, E)); + } else if (a === "queue" && o[0] === ":") { o.shift(); - a.queue = C(o, v); - } else if (f === "root" && o[0] === ":") { + f.queue = O(o, E); + } else if (a === "root" && o[0] === ":") { o.shift(); - a[f] = rt(o); - } else if (f === "threshold" && o[0] === ":") { + f[a] = rt(o); + } else if (a === "threshold" && o[0] === ":") { o.shift(); - a[f] = C(o, v); + f[a] = O(o, E); } else { fe(e, "htmx:syntax:error", { token: o.shift() }); } - C(o, w); + O(o, C); } - r.push(a); + r.push(f); } } if (o.length === l) { fe(e, "htmx:syntax:error", { token: o.shift() }); } - C(o, w); + O(o, C); } while (o[0] === "," && o.shift()); if (n) { n[t] = r; @@ -1367,7 +1385,7 @@ var htmx = (function () { return r; } function st(e) { - const t = te(e, "hx-trigger"); + const t = a(e, "hx-trigger"); let n = []; if (t) { const r = Q.config.triggerSpecsCache; @@ -1386,13 +1404,13 @@ var htmx = (function () { } } function lt(e) { - ie(e).cancelled = true; + oe(e).cancelled = true; } function ct(e, t, n) { - const r = ie(e); - r.timeout = E().setTimeout(function () { - if (le(e) && r.cancelled !== true) { - if (!gt(n, e, Mt("hx:poll:trigger", { triggerSpec: n, target: e }))) { + const r = oe(e); + r.timeout = b().setTimeout(function () { + if (se(e) && r.cancelled !== true) { + if (!pt(n, e, Bt("hx:poll:trigger", { triggerSpec: n, target: e }))) { t(e); } ct(e, t, n); @@ -1406,10 +1424,10 @@ var htmx = (function () { ee(e, "href").indexOf("#") !== 0 ); } - function at(e) { + function ft(e) { return g(e, Q.config.disableSelector); } - function ft(t, n, e) { + function at(t, n, e) { if ( (t instanceof HTMLAnchorElement && ut(t) && @@ -1427,22 +1445,22 @@ var htmx = (function () { r = i ? i.toLowerCase() : "get"; o = ee(t, "action"); if (o == null || o === "") { - o = ne().location.href; + o = location.href; } if (r === "get" && o.includes("?")) { o = o.replace(/\?[^#]+/, ""); } } e.forEach(function (e) { - pt( + gt( t, function (e, t) { - const n = ue(e); - if (at(n)) { - b(n); + const n = ce(e); + if (ft(n)) { + S(n); return; } - de(r, o, n, t); + he(r, o, n, t); }, n, e, @@ -1452,25 +1470,20 @@ var htmx = (function () { } } function ht(e, t) { - const n = ue(t); - if (!n) { - return false; - } if (e.type === "submit" || e.type === "click") { - if (n.tagName === "FORM") { + t = ce(e.target) || t; + if (t.tagName === "FORM") { return true; } - if ( - h(n, 'input[type="submit"], button') && - (h(n, "[form]") || g(n, "form") !== null) - ) { + if (t.form && t.type === "submit") { return true; } + t = t.closest("a"); if ( - n instanceof HTMLAnchorElement && - n.href && - (n.getAttribute("href") === "#" || - n.getAttribute("href").indexOf("#") !== 0) + t && + t.href && + (t.getAttribute("href") === "#" || + t.getAttribute("href").indexOf("#") !== 0) ) { return true; } @@ -1479,60 +1492,60 @@ var htmx = (function () { } function dt(e, t) { return ( - ie(e).boosted && + oe(e).boosted && e instanceof HTMLAnchorElement && t.type === "click" && (t.ctrlKey || t.metaKey) ); } - function gt(e, t, n) { + function pt(e, t, n) { const r = e.eventFilter; if (r) { try { return r.call(t, n) !== true; } catch (e) { const o = r.source; - fe(ne().body, "htmx:eventFilter:error", { error: e, source: o }); + fe(te().body, "htmx:eventFilter:error", { error: e, source: o }); return true; } } return false; } - function pt(l, c, e, u, a) { - const f = ie(l); + function gt(l, c, e, u, f) { + const a = oe(l); let t; if (u.from) { - t = p(l, u.from); + t = m(l, u.from); } else { t = [l]; } if (u.changed) { - if (!("lastValue" in f)) { - f.lastValue = new WeakMap(); + if (!("lastValue" in a)) { + a.lastValue = new WeakMap(); } t.forEach(function (e) { - if (!f.lastValue.has(u)) { - f.lastValue.set(u, new WeakMap()); + if (!a.lastValue.has(u)) { + a.lastValue.set(u, new WeakMap()); } - f.lastValue.get(u).set(e, e.value); + a.lastValue.get(u).set(e, e.value); }); } - se(t, function (i) { + ie(t, function (i) { const s = function (e) { - if (!le(l)) { + if (!se(l)) { i.removeEventListener(u.trigger, s); return; } if (dt(l, e)) { return; } - if (a || ht(e, l)) { + if (f || ht(e, l)) { e.preventDefault(); } - if (gt(u, l, e)) { + if (pt(u, l, e)) { return; } - const t = ie(e); + const t = oe(e); t.triggerSpec = u; if (t.handledFor == null) { t.handledFor = []; @@ -1543,47 +1556,47 @@ var htmx = (function () { e.stopPropagation(); } if (u.target && e.target) { - if (!h(ue(e.target), u.target)) { + if (!h(ce(e.target), u.target)) { return; } } if (u.once) { - if (f.triggeredOnce) { + if (a.triggeredOnce) { return; } else { - f.triggeredOnce = true; + a.triggeredOnce = true; } } if (u.changed) { - const n = event.target; + const n = e.target; const r = n.value; - const o = f.lastValue.get(u); + const o = a.lastValue.get(u); if (o.has(n) && o.get(n) === r) { return; } o.set(n, r); } - if (f.delayed) { - clearTimeout(f.delayed); + if (a.delayed) { + clearTimeout(a.delayed); } - if (f.throttle) { + if (a.throttle) { return; } if (u.throttle > 0) { - if (!f.throttle) { - he(l, "htmx:trigger"); + if (!a.throttle) { + ae(l, "htmx:trigger"); c(l, e); - f.throttle = E().setTimeout(function () { - f.throttle = null; + a.throttle = b().setTimeout(function () { + a.throttle = null; }, u.throttle); } } else if (u.delay > 0) { - f.delayed = E().setTimeout(function () { - he(l, "htmx:trigger"); + a.delayed = b().setTimeout(function () { + ae(l, "htmx:trigger"); c(l, e); }, u.delay); } else { - he(l, "htmx:trigger"); + ae(l, "htmx:trigger"); c(l, e); } } @@ -1596,19 +1609,19 @@ var htmx = (function () { }); } let mt = false; - let xt = null; - function yt() { - if (!xt) { - xt = function () { + let yt = null; + function xt() { + if (!yt) { + yt = function () { mt = true; }; - window.addEventListener("scroll", xt); - window.addEventListener("resize", xt); + window.addEventListener("scroll", yt); + window.addEventListener("resize", yt); setInterval(function () { if (mt) { mt = false; - se( - ne().querySelectorAll( + ie( + te().querySelectorAll( "[hx-trigger*='revealed'],[data-hx-trigger*='revealed']", ), function (e) { @@ -1620,16 +1633,16 @@ var htmx = (function () { } } function bt(e) { - if (!s(e, "data-hx-revealed") && X(e)) { + if (!s(e, "data-hx-revealed") && F(e)) { e.setAttribute("data-hx-revealed", "true"); - const t = ie(e); + const t = oe(e); if (t.initHash) { - he(e, "revealed"); + ae(e, "revealed"); } else { e.addEventListener( "htmx:afterProcessNode", function () { - he(e, "revealed"); + ae(e, "revealed"); }, { once: true }, ); @@ -1640,32 +1653,32 @@ var htmx = (function () { const o = function () { if (!n.loaded) { n.loaded = true; - he(e, "htmx:trigger"); + ae(e, "htmx:trigger"); t(e); } }; if (r > 0) { - E().setTimeout(o, r); + b().setTimeout(o, r); } else { o(); } } function wt(t, n, e) { let i = false; - se(r, function (r) { + ie(de, function (r) { if (s(t, "hx-" + r)) { - const o = te(t, "hx-" + r); + const o = a(t, "hx-" + r); i = true; n.path = o; n.verb = r; e.forEach(function (e) { St(t, e, n, function (e, t) { - const n = ue(e); - if (g(n, Q.config.disableSelector)) { - b(n); + const n = ce(e); + if (ft(n)) { + S(n); return; } - de(r, o, n, t); + he(r, o, n, t); }); }); } @@ -1674,13 +1687,13 @@ var htmx = (function () { } function St(r, e, t, n) { if (e.trigger === "revealed") { - yt(); - pt(r, n, t, e); - bt(ue(r)); + xt(); + gt(r, n, t, e); + bt(ce(r)); } else if (e.trigger === "intersect") { const o = {}; if (e.root) { - o.root = ae(r, e.root); + o.root = ue(r, e.root); } if (e.threshold) { o.threshold = parseFloat(e.threshold); @@ -1689,26 +1702,26 @@ var htmx = (function () { for (let e = 0; e < t.length; e++) { const n = t[e]; if (n.isIntersecting) { - he(r, "intersect"); + ae(r, "intersect"); break; } } }, o); - i.observe(ue(r)); - pt(ue(r), n, t, e); + i.observe(ce(r)); + gt(ce(r), n, t, e); } else if (!t.firstInitCompleted && e.trigger === "load") { - if (!gt(e, r, Mt("load", { elt: r }))) { - vt(ue(r), n, t, e.delay); + if (!pt(e, r, Bt("load", { elt: r }))) { + vt(ce(r), n, t, e.delay); } } else if (e.pollInterval > 0) { t.polling = true; - ct(ue(r), n, e); + ct(ce(r), n, e); } else { - pt(r, n, t, e); + gt(r, n, t, e); } } function Et(e) { - const t = ue(e); + const t = ce(e); if (!t) { return false; } @@ -1732,11 +1745,11 @@ var htmx = (function () { ); function Ot(e, t) { if (Et(e)) { - t.push(ue(e)); + t.push(ce(e)); } const n = Ct.evaluate(e); let r = null; - while ((r = n.iterateNext())) t.push(ue(r)); + while ((r = n.iterateNext())) t.push(ce(r)); } function Rt(e) { const t = []; @@ -1754,8 +1767,8 @@ var htmx = (function () { const n = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; const r = []; - for (const i in Mn) { - const s = Mn[i]; + for (const i in Vn) { + const s = Vn[i]; if (s.getSelectors) { var t = s.getSelectors(); if (t) { @@ -1764,7 +1777,7 @@ var htmx = (function () { } } const o = e.querySelectorAll( - H + + T + n + ", form, [type='submit']," + " [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]" + @@ -1779,43 +1792,46 @@ var htmx = (function () { } } function Tt(e) { - const t = g(ue(e.target), "button, input[type='submit']"); - const n = Lt(e); + const t = At(e.target); + const n = Nt(e); if (n) { n.lastButtonClicked = t; } } function qt(e) { - const t = Lt(e); + const t = Nt(e); if (t) { t.lastButtonClicked = null; } } + function At(e) { + return g(ce(e), "button, input[type='submit']"); + } function Lt(e) { - const t = g(ue(e.target), "button, input[type='submit']"); + return e.form || g(e, "form"); + } + function Nt(e) { + const t = At(e.target); if (!t) { return; } - const n = y("#" + ee(t, "form"), t.getRootNode()) || g(t, "form"); - if (!n) { - return; - } - return ie(n); + const n = Lt(t); + return oe(n); } - function At(e) { + function It(e) { e.addEventListener("click", Tt); e.addEventListener("focusin", Tt); e.addEventListener("focusout", qt); } - function Nt(t, e, n) { - const r = ie(t); + function Pt(t, e, n) { + const r = oe(t); if (!Array.isArray(r.onHandlers)) { r.onHandlers = []; } let o; const i = function (e) { - vn(t, function () { - if (at(t)) { + On(t, function () { + if (ft(t)) { return; } if (!o) { @@ -1827,8 +1843,8 @@ var htmx = (function () { t.addEventListener(e, i); r.onHandlers.push({ event: e, listener: i }); } - function It(t) { - ke(t); + function Dt(t) { + De(t); for (let e = 0; e < t.attributes.length; e++) { const n = t.attributes[e].name; const r = t.attributes[e].value; @@ -1844,138 +1860,144 @@ var htmx = (function () { } else if (l(e, "htmx-")) { e = "htmx:" + e.slice(5); } - Nt(t, e, r); + Pt(t, e, r); } } } } - function Pt(t) { - if (g(t, Q.config.disableSelector)) { - b(t); - return; - } - const n = ie(t); - const e = Pe(t); - if (n.initHash !== e) { - De(t); - n.initHash = e; - he(t, "htmx:beforeProcessNode"); - const r = st(t); - const o = wt(t, n, r); - if (!o) { - if (re(t, "hx-boost") === "true") { - ft(t, n, r); - } else if (s(t, "hx-trigger")) { - r.forEach(function (e) { - St(t, e, n, function () {}); - }); - } - } - if ( - t.tagName === "FORM" || - (ee(t, "type") === "submit" && s(t, "form")) - ) { - At(t); + function kt(t) { + ae(t, "htmx:beforeProcessNode"); + const n = oe(t); + const e = st(t); + const r = wt(t, n, e); + if (!r) { + if (ne(t, "hx-boost") === "true") { + at(t, n, e); + } else if (s(t, "hx-trigger")) { + e.forEach(function (e) { + St(t, e, n, function () {}); + }); } - n.firstInitCompleted = true; - he(t, "htmx:afterProcessNode"); } + if (t.tagName === "FORM" || (ee(t, "type") === "submit" && s(t, "form"))) { + It(t); + } + n.firstInitCompleted = true; + ae(t, "htmx:afterProcessNode"); + } + function Mt(e) { + if (!(e instanceof Element)) { + return false; + } + const t = oe(e); + const n = Pe(e); + if (t.initHash !== n) { + ke(e); + t.initHash = n; + return true; + } + return false; } - function kt(e) { - e = y(e); - if (g(e, Q.config.disableSelector)) { - b(e); + function Ft(e) { + e = w(e); + if (ft(e)) { + S(e); return; } - Pt(e); - se(Ht(e), function (e) { - Pt(e); + const t = []; + if (Mt(e)) { + t.push(e); + } + ie(Ht(e), function (e) { + if (ft(e)) { + S(e); + return; + } + if (Mt(e)) { + t.push(e); + } }); - se(Rt(e), It); + ie(Rt(e), Dt); + ie(t, kt); } - function Dt(e) { + function Xt(e) { return e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(); } - function Mt(e, t) { - let n; - if (window.CustomEvent && typeof window.CustomEvent === "function") { - n = new CustomEvent(e, { - bubbles: true, - cancelable: true, - composed: true, - detail: t, - }); - } else { - n = ne().createEvent("CustomEvent"); - n.initCustomEvent(e, true, true, t); - } - return n; + function Bt(e, t) { + return new CustomEvent(e, { + bubbles: true, + cancelable: true, + composed: true, + detail: t, + }); } function fe(e, t, n) { - he(e, t, ce({ error: t }, n)); + ae(e, t, le({ error: t }, n)); } - function Xt(e) { + function Ut(e) { return e === "htmx:afterProcessNode"; } - function Ft(e, t) { - se(Un(e), function (e) { + function jt(e, t, n) { + ie(Jn(e, [], n), function (e) { try { t(e); } catch (e) { - O(e); + R(e); } }); } - function O(e) { - if (console.error) { - console.error(e); - } else if (console.log) { - console.log("ERROR: ", e); - } + function R(e) { + console.error(e); } - function he(e, t, n) { - e = y(e); + function ae(e, t, n) { + e = w(e); if (n == null) { n = {}; } n.elt = e; - const r = Mt(t, n); - if (Q.logger && !Xt(t)) { + const r = Bt(t, n); + if (Q.logger && !Ut(t)) { Q.logger(e, t, n); } if (n.error) { - O(n.error); - he(e, "htmx:error", { errorInfo: n }); + R(n.error); + ae(e, "htmx:error", { errorInfo: n }); } let o = e.dispatchEvent(r); - const i = Dt(t); + const i = Xt(t); if (o && i !== t) { - const s = Mt(i, r.detail); + const s = Bt(i, r.detail); o = o && e.dispatchEvent(s); } - Ft(ue(e), function (e) { + jt(ce(e), function (e) { o = o && e.onEvent(t, r) !== false && !r.defaultPrevented; }); return o; } - let Bt = location.pathname + location.search; - function Ut() { - const e = ne().querySelector("[hx-history-elt],[data-hx-history-elt]"); - return e || ne().body; + let Vt = location.pathname + location.search; + function _t(e) { + Vt = e; + if (B()) { + sessionStorage.setItem("htmx-current-path-for-history", e); + } } - function jt(t, e) { + function zt() { + const e = te().querySelector("[hx-history-elt],[data-hx-history-elt]"); + return e || te().body; + } + function $t(t, e) { if (!B()) { return; } - const n = _t(e); - const r = ne().title; + const n = Kt(e); + const r = te().title; const o = window.scrollY; if (Q.config.historyCacheSize <= 0) { - localStorage.removeItem("htmx-history-cache"); + sessionStorage.removeItem("htmx-history-cache"); return; } t = U(t); - const i = S(localStorage.getItem("htmx-history-cache")) || []; + const i = v(sessionStorage.getItem("htmx-history-cache")) || []; for (let e = 0; e < i.length; e++) { if (i[e].url === t) { i.splice(e, 1); @@ -1983,27 +2005,27 @@ var htmx = (function () { } } const s = { url: t, content: n, title: r, scroll: o }; - he(ne().body, "htmx:historyItemCreated", { item: s, cache: i }); + ae(te().body, "htmx:historyItemCreated", { item: s, cache: i }); i.push(s); while (i.length > Q.config.historyCacheSize) { i.shift(); } while (i.length > 0) { try { - localStorage.setItem("htmx-history-cache", JSON.stringify(i)); + sessionStorage.setItem("htmx-history-cache", JSON.stringify(i)); break; } catch (e) { - fe(ne().body, "htmx:historyCacheError", { cause: e, cache: i }); + fe(te().body, "htmx:historyCacheError", { cause: e, cache: i }); i.shift(); } } } - function Vt(t) { + function Jt(t) { if (!B()) { return null; } t = U(t); - const n = S(localStorage.getItem("htmx-history-cache")) || []; + const n = v(sessionStorage.getItem("htmx-history-cache")) || []; for (let e = 0; e < n.length; e++) { if (n[e].url === t) { return n[e]; @@ -2011,36 +2033,35 @@ var htmx = (function () { } return null; } - function _t(e) { + function Kt(e) { const t = Q.config.requestClass; const n = e.cloneNode(true); - se(x(n, "." + t), function (e) { + ie(x(n, "." + t), function (e) { G(e, t); }); - se(x(n, "[data-disabled-by-htmx]"), function (e) { + ie(x(n, "[data-disabled-by-htmx]"), function (e) { e.removeAttribute("disabled"); }); return n.innerHTML; } - function zt() { - const e = Ut(); - const t = Bt || location.pathname + location.search; - let n; - try { - n = ne().querySelector( - '[hx-history="false" i],[data-hx-history="false" i]', - ); - } catch (e) { - n = ne().querySelector('[hx-history="false"],[data-hx-history="false"]'); + function Gt() { + const e = zt(); + let t = Vt; + if (B()) { + t = sessionStorage.getItem("htmx-current-path-for-history"); } + t = t || location.pathname + location.search; + const n = te().querySelector( + '[hx-history="false" i],[data-hx-history="false" i]', + ); if (!n) { - he(ne().body, "htmx:beforeHistorySave", { path: t, historyElt: e }); - jt(t, e); + ae(te().body, "htmx:beforeHistorySave", { path: t, historyElt: e }); + $t(t, e); } if (Q.config.historyEnabled) - history.replaceState({ htmx: true }, ne().title, window.location.href); + history.replaceState({ htmx: true }, te().title, location.href); } - function $t(e) { + function Wt(e) { if (Q.config.getCacheBusterParam) { e = e.replace(/org\.htmx\.cache-buster=[^&]*&?/, ""); if (Y(e, "&") || Y(e, "?")) { @@ -2050,121 +2071,122 @@ var htmx = (function () { if (Q.config.historyEnabled) { history.pushState({ htmx: true }, "", e); } - Bt = e; + _t(e); } - function Jt(e) { + function Zt(e) { if (Q.config.historyEnabled) history.replaceState({ htmx: true }, "", e); - Bt = e; + _t(e); } - function Kt(e) { - se(e, function (e) { + function Yt(e) { + ie(e, function (e) { e.call(undefined); }); } - function Gt(o) { - const e = new XMLHttpRequest(); - const i = { path: o, xhr: e }; - he(ne().body, "htmx:historyCacheMiss", i); - e.open("GET", o, true); - e.setRequestHeader("HX-Request", "true"); - e.setRequestHeader("HX-History-Restore-Request", "true"); - e.setRequestHeader("HX-Current-URL", ne().location.href); - e.onload = function () { + function Qt(e) { + const t = new XMLHttpRequest(); + const n = { swapStyle: "innerHTML", swapDelay: 0, settleDelay: 0 }; + const r = { path: e, xhr: t, historyElt: zt(), swapSpec: n }; + t.open("GET", e, true); + if (Q.config.historyRestoreAsHxRequest) { + t.setRequestHeader("HX-Request", "true"); + } + t.setRequestHeader("HX-History-Restore-Request", "true"); + t.setRequestHeader("HX-Current-URL", location.href); + t.onload = function () { if (this.status >= 200 && this.status < 400) { - he(ne().body, "htmx:historyCacheMissLoad", i); - const e = P(this.response); - const t = - e.querySelector("[hx-history-elt],[data-hx-history-elt]") || e; - const n = Ut(); - const r = xn(n); - kn(e.title); - qe(e); - Ve(n, t, r); - Te(); - Kt(r.tasks); - Bt = o; - he(ne().body, "htmx:historyRestore", { - path: o, + r.response = this.response; + ae(te().body, "htmx:historyCacheMissLoad", r); + $e(r.historyElt, r.response, n, { + contextElement: r.historyElt, + historyRequest: true, + }); + _t(r.path); + ae(te().body, "htmx:historyRestore", { + path: e, cacheMiss: true, - serverResponse: this.response, + serverResponse: r.response, }); } else { - fe(ne().body, "htmx:historyCacheMissLoadError", i); + fe(te().body, "htmx:historyCacheMissLoadError", r); } }; - e.send(); + if (ae(te().body, "htmx:historyCacheMiss", r)) { + t.send(); + } } - function Wt(e) { - zt(); + function en(e) { + Gt(); e = e || location.pathname + location.search; - const t = Vt(e); + const t = Jt(e); if (t) { - const n = P(t.content); - const r = Ut(); - const o = xn(r); - kn(t.title); - qe(n); - Ve(r, n, o); - Te(); - Kt(o.tasks); - E().setTimeout(function () { - window.scrollTo(0, t.scroll); - }, 0); - Bt = e; - he(ne().body, "htmx:historyRestore", { path: e, item: t }); + const n = { + swapStyle: "innerHTML", + swapDelay: 0, + settleDelay: 0, + scroll: t.scroll, + }; + const r = { path: e, item: t, historyElt: zt(), swapSpec: n }; + if (ae(te().body, "htmx:historyCacheHit", r)) { + $e(r.historyElt, t.content, n, { + contextElement: r.historyElt, + title: t.title, + }); + _t(r.path); + ae(te().body, "htmx:historyRestore", r); + } } else { if (Q.config.refreshOnHistoryMiss) { - window.location.reload(true); + Q.location.reload(true); } else { - Gt(e); + Qt(e); } } } - function Zt(e) { + function tn(e) { let t = we(e, "hx-indicator"); if (t == null) { t = [e]; } - se(t, function (e) { - const t = ie(e); + ie(t, function (e) { + const t = oe(e); t.requestCount = (t.requestCount || 0) + 1; e.classList.add.call(e.classList, Q.config.requestClass); }); return t; } - function Yt(e) { + function nn(e) { let t = we(e, "hx-disabled-elt"); if (t == null) { t = []; } - se(t, function (e) { - const t = ie(e); + ie(t, function (e) { + const t = oe(e); t.requestCount = (t.requestCount || 0) + 1; e.setAttribute("disabled", ""); e.setAttribute("data-disabled-by-htmx", ""); }); return t; } - function Qt(e, t) { - se(e.concat(t), function (e) { - const t = ie(e); + function rn(e, t) { + ie(e.concat(t), function (e) { + const t = oe(e); t.requestCount = (t.requestCount || 1) - 1; }); - se(e, function (e) { - const t = ie(e); + ie(e, function (e) { + const t = oe(e); if (t.requestCount === 0) { e.classList.remove.call(e.classList, Q.config.requestClass); } }); - se(t, function (e) { - const t = ie(e); + ie(t, function (e) { + const t = oe(e); if (t.requestCount === 0) { e.removeAttribute("disabled"); e.removeAttribute("data-disabled-by-htmx"); } }); } - function en(t, n) { + function on(t, n) { for (let e = 0; e < t.length; e++) { const r = t[e]; if (r.isSameNode(n)) { @@ -2173,7 +2195,7 @@ var htmx = (function () { } return false; } - function tn(e) { + function sn(e) { const t = e; if ( t.name === "" || @@ -2197,7 +2219,7 @@ var htmx = (function () { } return true; } - function nn(t, e, n) { + function ln(t, e, n) { if (t != null && e != null) { if (Array.isArray(e)) { e.forEach(function (e) { @@ -2208,7 +2230,7 @@ var htmx = (function () { } } } - function rn(t, n, r) { + function cn(t, n, r) { if (t != null && n != null) { let e = r.getAll(t); if (Array.isArray(n)) { @@ -2217,64 +2239,66 @@ var htmx = (function () { e = e.filter((e) => e !== n); } r.delete(t); - se(e, (e) => r.append(t, e)); + ie(e, (e) => r.append(t, e)); } } - function on(t, n, r, o, i) { - if (o == null || en(t, o)) { + function un(e) { + if (e instanceof HTMLSelectElement && e.multiple) { + return M(e.querySelectorAll("option:checked")).map(function (e) { + return e.value; + }); + } + if (e instanceof HTMLInputElement && e.files) { + return M(e.files); + } + return e.value; + } + function fn(t, n, r, e, o) { + if (e == null || on(t, e)) { return; } else { - t.push(o); - } - if (tn(o)) { - const s = ee(o, "name"); - let e = o.value; - if (o instanceof HTMLSelectElement && o.multiple) { - e = M(o.querySelectorAll("option:checked")).map(function (e) { - return e.value; - }); - } - if (o instanceof HTMLInputElement && o.files) { - e = M(o.files); - } - nn(s, e, n); - if (i) { - sn(o, r); + t.push(e); + } + if (sn(e)) { + const i = ee(e, "name"); + ln(i, un(e), n); + if (o) { + an(e, r); } } - if (o instanceof HTMLFormElement) { - se(o.elements, function (e) { + if (e instanceof HTMLFormElement) { + ie(e.elements, function (e) { if (t.indexOf(e) >= 0) { - rn(e.name, e.value, n); + cn(e.name, un(e), n); } else { t.push(e); } - if (i) { - sn(e, r); + if (o) { + an(e, r); } }); - new FormData(o).forEach(function (e, t) { + new FormData(e).forEach(function (e, t) { if (e instanceof File && e.name === "") { return; } - nn(t, e, n); + ln(t, e, n); }); } } - function sn(e, t) { + function an(e, t) { const n = e; if (n.willValidate) { - he(n, "htmx:validation:validate"); + ae(n, "htmx:validation:validate"); if (!n.checkValidity()) { t.push({ elt: n, message: n.validationMessage, validity: n.validity }); - he(n, "htmx:validation:failed", { + ae(n, "htmx:validation:failed", { message: n.validationMessage, validity: n.validity, }); } } } - function ln(n, e) { + function hn(n, e) { for (const t of e.keys()) { n.delete(t); } @@ -2283,47 +2307,47 @@ var htmx = (function () { }); return n; } - function cn(e, t) { + function dn(e, t) { const n = []; const r = new FormData(); const o = new FormData(); const i = []; - const s = ie(e); - if (s.lastButtonClicked && !le(s.lastButtonClicked)) { + const s = oe(e); + if (s.lastButtonClicked && !se(s.lastButtonClicked)) { s.lastButtonClicked = null; } let l = (e instanceof HTMLFormElement && e.noValidate !== true) || - te(e, "hx-validate") === "true"; + a(e, "hx-validate") === "true"; if (s.lastButtonClicked) { l = l && s.lastButtonClicked.formNoValidate !== true; } if (t !== "get") { - on(n, o, i, g(e, "form"), l); + fn(n, o, i, Lt(e), l); } - on(n, r, i, e, l); + fn(n, r, i, e, l); if ( s.lastButtonClicked || e.tagName === "BUTTON" || (e.tagName === "INPUT" && ee(e, "type") === "submit") ) { const u = s.lastButtonClicked || e; - const a = ee(u, "name"); - nn(a, u.value, o); + const f = ee(u, "name"); + ln(f, u.value, o); } const c = we(e, "hx-include"); - se(c, function (e) { - on(n, r, i, ue(e), l); + ie(c, function (e) { + fn(n, r, i, ce(e), l); if (!h(e, "form")) { - se(f(e).querySelectorAll(ot), function (e) { - on(n, r, i, e, l); + ie(p(e).querySelectorAll(ot), function (e) { + fn(n, r, i, e, l); }); } }); - ln(r, o); - return { errors: i, formData: r, values: An(r) }; + hn(r, o); + return { errors: i, formData: r, values: kn(r) }; } - function un(e, t, n) { + function pn(e, t, n) { if (e !== "") { e += "&"; } @@ -2334,47 +2358,47 @@ var htmx = (function () { e += encodeURIComponent(t) + "=" + r; return e; } - function an(e) { - e = qn(e); + function gn(e) { + e = Pn(e); let n = ""; e.forEach(function (e, t) { - n = un(n, t, e); + n = pn(n, t, e); }); return n; } - function fn(e, t, n) { + function mn(e, t, n) { const r = { "HX-Request": "true", "HX-Trigger": ee(e, "id"), "HX-Trigger-Name": ee(e, "name"), - "HX-Target": te(t, "id"), - "HX-Current-URL": ne().location.href, + "HX-Target": a(t, "id"), + "HX-Current-URL": location.href, }; - bn(e, "hx-headers", false, r); + Cn(e, "hx-headers", false, r); if (n !== undefined) { r["HX-Prompt"] = n; } - if (ie(e).boosted) { + if (oe(e).boosted) { r["HX-Boosted"] = "true"; } return r; } - function hn(n, e) { - const t = re(e, "hx-params"); + function yn(n, e) { + const t = ne(e, "hx-params"); if (t) { if (t === "none") { return new FormData(); } else if (t === "*") { return n; } else if (t.indexOf("not ") === 0) { - se(t.slice(4).split(","), function (e) { + ie(t.slice(4).split(","), function (e) { e = e.trim(); n.delete(e); }); return n; } else { const r = new FormData(); - se(t.split(","), function (t) { + ie(t.split(","), function (t) { t = t.trim(); if (n.has(t)) { n.getAll(t).forEach(function (e) { @@ -2388,21 +2412,21 @@ var htmx = (function () { return n; } } - function dn(e) { + function xn(e) { return !!ee(e, "href") && ee(e, "href").indexOf("#") >= 0; } - function gn(e, t) { - const n = t || re(e, "hx-swap"); + function bn(e, t) { + const n = t || ne(e, "hx-swap"); const r = { - swapStyle: ie(e).boosted ? "innerHTML" : Q.config.defaultSwapStyle, + swapStyle: oe(e).boosted ? "innerHTML" : Q.config.defaultSwapStyle, swapDelay: Q.config.defaultSwapDelay, settleDelay: Q.config.defaultSettleDelay, }; - if (Q.config.scrollIntoViewOnBoost && ie(e).boosted && !dn(e)) { + if (Q.config.scrollIntoViewOnBoost && oe(e).boosted && !xn(e)) { r.show = "top"; } if (n) { - const s = F(n); + const s = X(n); if (s.length > 0) { for (let e = 0; e < s.length; e++) { const l = s[e]; @@ -2422,11 +2446,11 @@ var htmx = (function () { r.scroll = u; r.scrollTarget = i; } else if (l.indexOf("show:") === 0) { - const a = l.slice(5); - var o = a.split(":"); - const f = o.pop(); + const f = l.slice(5); + var o = f.split(":"); + const a = o.pop(); var i = o.length > 0 ? o.join(":") : null; - r.show = f; + r.show = a; r.showTarget = i; } else if (l.indexOf("focus-scroll:") === 0) { const h = l.slice("focus-scroll:".length); @@ -2434,22 +2458,22 @@ var htmx = (function () { } else if (e == 0) { r.swapStyle = l; } else { - O("Unknown modifier in hx-swap: " + l); + R("Unknown modifier in hx-swap: " + l); } } } } return r; } - function pn(e) { + function vn(e) { return ( - re(e, "hx-encoding") === "multipart/form-data" || + ne(e, "hx-encoding") === "multipart/form-data" || (h(e, "form") && ee(e, "enctype") === "multipart/form-data") ); } - function mn(t, n, r) { + function wn(t, n, r) { let o = null; - Ft(n, function (e) { + jt(n, function (e) { if (o == null) { o = e.encodeParameters(t, r, n); } @@ -2457,23 +2481,23 @@ var htmx = (function () { if (o != null) { return o; } else { - if (pn(n)) { - return ln(new FormData(), qn(r)); + if (vn(n)) { + return hn(new FormData(), Pn(r)); } else { - return an(r); + return gn(r); } } } - function xn(e) { + function Sn(e) { return { tasks: [], elts: [e] }; } - function yn(e, t) { + function En(e, t) { const n = e[0]; const r = e[e.length - 1]; if (t.scroll) { var o = null; if (t.scrollTarget) { - o = ue(ae(n, t.scrollTarget)); + o = ce(ue(n, t.scrollTarget)); } if (t.scroll === "top" && (n || o)) { o = o || n; @@ -2483,6 +2507,11 @@ var htmx = (function () { o = o || r; o.scrollTop = o.scrollHeight; } + if (typeof t.scroll === "number") { + b().setTimeout(function () { + window.scrollTo(0, t.scroll); + }, 0); + } } if (t.show) { var o = null; @@ -2491,7 +2520,7 @@ var htmx = (function () { if (t.showTarget === "window") { e = "body"; } - o = ue(ae(n, e)); + o = ce(ue(n, e)); } if (t.show === "top" && (n || o)) { o = o || n; @@ -2503,16 +2532,16 @@ var htmx = (function () { } } } - function bn(r, e, o, i) { + function Cn(r, e, o, i, s) { if (i == null) { i = {}; } if (r == null) { return i; } - const s = te(r, e); - if (s) { - let e = s.trim(); + const l = a(r, e); + if (l) { + let e = l.trim(); let t = o; if (e === "unset") { return null; @@ -2529,27 +2558,31 @@ var htmx = (function () { } let n; if (t) { - n = vn( + n = On( r, function () { - return Function("return (" + e + ")")(); + if (s) { + return Function("event", "return (" + e + ")").call(r, s); + } else { + return Function("return (" + e + ")").call(r); + } }, {}, ); } else { - n = S(e); + n = v(e); } - for (const l in n) { - if (n.hasOwnProperty(l)) { - if (i[l] == null) { - i[l] = n[l]; + for (const c in n) { + if (n.hasOwnProperty(c)) { + if (i[c] == null) { + i[c] = n[c]; } } } } - return bn(ue(c(r)), e, o, i); + return Cn(ce(u(r)), e, o, i, s); } - function vn(e, t, n) { + function On(e, t, n) { if (Q.config.allowEval) { return t(); } else { @@ -2557,16 +2590,16 @@ var htmx = (function () { return n; } } - function wn(e, t) { - return bn(e, "hx-vars", true, t); + function Rn(e, t, n) { + return Cn(e, "hx-vars", true, n, t); } - function Sn(e, t) { - return bn(e, "hx-vals", false, t); + function Hn(e, t, n) { + return Cn(e, "hx-vals", false, n, t); } - function En(e) { - return ce(wn(e), Sn(e)); + function Tn(e, t) { + return le(Rn(e, t), Hn(e, t)); } - function Cn(t, n, r) { + function qn(t, n, r) { if (r !== null) { try { t.setRequestHeader(n, r); @@ -2576,33 +2609,33 @@ var htmx = (function () { } } } - function On(t) { - if (t.responseURL && typeof URL !== "undefined") { + function An(t) { + if (t.responseURL) { try { const e = new URL(t.responseURL); return e.pathname + e.search; } catch (e) { - fe(ne().body, "htmx:badResponseUrl", { url: t.responseURL }); + fe(te().body, "htmx:badResponseUrl", { url: t.responseURL }); } } } - function R(e, t) { + function H(e, t) { return t.test(e.getAllResponseHeaders()); } - function Rn(t, n, r) { + function Ln(t, n, r) { t = t.toLowerCase(); if (r) { if (r instanceof Element || typeof r === "string") { - return de(t, n, null, null, { - targetOverride: y(r) || ve, + return he(t, n, null, null, { + targetOverride: w(r) || ve, returnPromise: true, }); } else { - let e = y(r.target); - if ((r.target && !e) || (r.source && !e && !y(r.source))) { + let e = w(r.target); + if ((r.target && !e) || (r.source && !e && !w(r.source))) { e = ve; } - return de(t, n, y(r.source), r.event, { + return he(t, n, w(r.source), r.event, { handler: r.handler, headers: r.headers, values: r.values, @@ -2613,10 +2646,10 @@ var htmx = (function () { }); } } else { - return de(t, n, null, null, { returnPromise: true }); + return he(t, n, null, null, { returnPromise: true }); } } - function Hn(e) { + function Nn(e) { const t = []; while (e) { t.push(e); @@ -2624,25 +2657,21 @@ var htmx = (function () { } return t; } - function Tn(e, t, n) { - let r; - let o; - if (typeof URL === "function") { - o = new URL(t, document.location.href); - const i = document.location.origin; - r = i === o.origin; - } else { - o = t; - r = l(t, document.location.origin); - } + function In(e, t, n) { + const r = new URL( + t, + location.protocol !== "about:" ? location.href : window.origin, + ); + const o = location.protocol !== "about:" ? location.origin : window.origin; + const i = o === r.origin; if (Q.config.selfRequestsOnly) { - if (!r) { + if (!i) { return false; } } - return he(e, "htmx:validateUrl", ce({ url: o, sameHost: r }, n)); + return ae(e, "htmx:validateUrl", le({ url: r, sameHost: i }, n)); } - function qn(e) { + function Pn(e) { if (e instanceof FormData) return e; const t = new FormData(); for (const n in e) { @@ -2660,7 +2689,7 @@ var htmx = (function () { } return t; } - function Ln(r, o, e) { + function Dn(r, o, e) { return new Proxy(e, { get: function (t, e) { if (typeof e === "number") return t[e]; @@ -2696,7 +2725,7 @@ var htmx = (function () { }, }); } - function An(o) { + function kn(o) { return new Proxy(o, { get: function (e, t) { if (typeof t === "symbol") { @@ -2717,8 +2746,6 @@ var htmx = (function () { return function () { return o[t].apply(o, arguments); }; - } else { - return e[t]; } } const n = o.getAll(t); @@ -2727,7 +2754,7 @@ var htmx = (function () { } else if (n.length === 1) { return n[0]; } else { - return Ln(e, t, n); + return Dn(e, t, n); } }, set: function (t, n, e) { @@ -2760,7 +2787,7 @@ var htmx = (function () { }, }); } - function de(t, n, r, o, i, D) { + function he(t, n, r, o, i, k) { let s = null; let l = null; i = i != null ? i : {}; @@ -2771,38 +2798,41 @@ var htmx = (function () { }); } if (r == null) { - r = ne().body; + r = te().body; } - const M = i.handler || Dn; - const X = i.select || null; - if (!le(r)) { - oe(s); + const M = i.handler || jn; + const F = i.select || null; + if (!se(r)) { + re(s); return e; } - const c = i.targetOverride || ue(Ee(r)); + const c = i.targetOverride || ce(Ee(r)); if (c == null || c == ve) { - fe(r, "htmx:targetError", { target: te(r, "hx-target") }); - oe(l); + fe(r, "htmx:targetError", { target: ne(r, "hx-target") }); + re(l); return e; } - let u = ie(r); - const a = u.lastButtonClicked; - if (a) { - const L = ee(a, "formaction"); - if (L != null) { - n = L; - } - const A = ee(a, "formmethod"); + let u = oe(r); + const f = u.lastButtonClicked; + if (f) { + const A = ee(f, "formaction"); if (A != null) { - if (A.toLowerCase() !== "dialog") { - t = A; + n = A; + } + const L = ee(f, "formmethod"); + if (L != null) { + if (de.includes(L.toLowerCase())) { + t = L; + } else { + re(s); + return e; } } } - const f = re(r, "hx-confirm"); - if (D === undefined) { + const a = ne(r, "hx-confirm"); + if (k === undefined) { const K = function (e) { - return de(t, n, r, o, i, !!e); + return he(t, n, r, o, i, !!e); }; const G = { target: c, @@ -2812,83 +2842,83 @@ var htmx = (function () { triggeringEvent: o, etc: i, issueRequest: K, - question: f, + question: a, }; - if (he(r, "htmx:confirm", G) === false) { - oe(s); + if (ae(r, "htmx:confirm", G) === false) { + re(s); return e; } } let h = r; - let d = re(r, "hx-sync"); - let g = null; - let F = false; + let d = ne(r, "hx-sync"); + let p = null; + let X = false; if (d) { const N = d.split(":"); const I = N[0].trim(); if (I === "this") { h = Se(r, "hx-sync"); } else { - h = ue(ae(r, I)); + h = ce(ue(r, I)); } d = (N[1] || "drop").trim(); - u = ie(h); + u = oe(h); if (d === "drop" && u.xhr && u.abortable !== true) { - oe(s); + re(s); return e; } else if (d === "abort") { if (u.xhr) { - oe(s); + re(s); return e; } else { - F = true; + X = true; } } else if (d === "replace") { - he(h, "htmx:abort"); + ae(h, "htmx:abort"); } else if (d.indexOf("queue") === 0) { const W = d.split(" "); - g = (W[1] || "last").trim(); + p = (W[1] || "last").trim(); } } if (u.xhr) { if (u.abortable) { - he(h, "htmx:abort"); + ae(h, "htmx:abort"); } else { - if (g == null) { + if (p == null) { if (o) { - const P = ie(o); + const P = oe(o); if (P && P.triggerSpec && P.triggerSpec.queue) { - g = P.triggerSpec.queue; + p = P.triggerSpec.queue; } } - if (g == null) { - g = "last"; + if (p == null) { + p = "last"; } } if (u.queuedRequests == null) { u.queuedRequests = []; } - if (g === "first" && u.queuedRequests.length === 0) { + if (p === "first" && u.queuedRequests.length === 0) { u.queuedRequests.push(function () { - de(t, n, r, o, i); + he(t, n, r, o, i); }); - } else if (g === "all") { + } else if (p === "all") { u.queuedRequests.push(function () { - de(t, n, r, o, i); + he(t, n, r, o, i); }); - } else if (g === "last") { + } else if (p === "last") { u.queuedRequests = []; u.queuedRequests.push(function () { - de(t, n, r, o, i); + he(t, n, r, o, i); }); } - oe(s); + re(s); return e; } } - const p = new XMLHttpRequest(); - u.xhr = p; - u.abortable = F; + const g = new XMLHttpRequest(); + u.xhr = g; + u.abortable = X; const m = function () { u.xhr = null; u.abortable = false; @@ -2897,55 +2927,56 @@ var htmx = (function () { e(); } }; - const B = re(r, "hx-prompt"); + const B = ne(r, "hx-prompt"); if (B) { - var x = prompt(B); - if (x === null || !he(r, "htmx:prompt", { prompt: x, target: c })) { - oe(s); + var y = prompt(B); + if (y === null || !ae(r, "htmx:prompt", { prompt: y, target: c })) { + re(s); m(); return e; } } - if (f && !D) { - if (!confirm(f)) { - oe(s); + if (a && !k) { + if (!confirm(a)) { + re(s); m(); return e; } } - let y = fn(r, c, x); - if (t !== "get" && !pn(r)) { - y["Content-Type"] = "application/x-www-form-urlencoded"; + let x = mn(r, c, y); + if (t !== "get" && !vn(r)) { + x["Content-Type"] = "application/x-www-form-urlencoded"; } if (i.headers) { - y = ce(y, i.headers); + x = le(x, i.headers); } - const U = cn(r, t); + const U = dn(r, t); let b = U.errors; const j = U.formData; if (i.values) { - ln(j, qn(i.values)); + hn(j, Pn(i.values)); } - const V = qn(En(r)); - const v = ln(j, V); - let w = hn(v, r); + const V = Pn(Tn(r, o)); + const v = hn(j, V); + let w = yn(v, r); if (Q.config.getCacheBusterParam && t === "get") { w.set("org.htmx.cache-buster", ee(c, "id") || "true"); } if (n == null || n === "") { - n = ne().location.href; + n = location.href; } - const S = bn(r, "hx-request"); - const _ = ie(r).boosted; + const S = Cn(r, "hx-request"); + const _ = oe(r).boosted; let E = Q.config.methodsThatUseUrlParams.indexOf(t) >= 0; const C = { boosted: _, useUrlParams: E, formData: w, - parameters: An(w), + parameters: kn(w), unfilteredFormData: v, - unfilteredParameters: An(v), - headers: y, + unfilteredParameters: kn(v), + headers: x, + elt: r, target: c, verb: t, errors: b, @@ -2955,20 +2986,20 @@ var htmx = (function () { path: n, triggeringEvent: o, }; - if (!he(r, "htmx:configRequest", C)) { - oe(s); + if (!ae(r, "htmx:configRequest", C)) { + re(s); m(); return e; } n = C.path; t = C.verb; - y = C.headers; - w = qn(C.parameters); + x = C.headers; + w = Pn(C.parameters); b = C.errors; E = C.useUrlParams; if (b && b.length > 0) { - he(r, "htmx:validation:halted", C); - oe(s); + ae(r, "htmx:validation:halted", C); + re(s); m(); return e; } @@ -2985,37 +3016,38 @@ var htmx = (function () { } else { R += "&"; } - R += an(w); + R += gn(w); if (O) { R += "#" + O; } } } - if (!Tn(r, R, C)) { + if (!In(r, R, C)) { fe(r, "htmx:invalidPath", C); - oe(l); + re(l); + m(); return e; } - p.open(t.toUpperCase(), R, true); - p.overrideMimeType("text/html"); - p.withCredentials = C.withCredentials; - p.timeout = C.timeout; + g.open(t.toUpperCase(), R, true); + g.overrideMimeType("text/html"); + g.withCredentials = C.withCredentials; + g.timeout = C.timeout; if (S.noHeaders) { } else { - for (const k in y) { - if (y.hasOwnProperty(k)) { - const Y = y[k]; - Cn(p, k, Y); + for (const D in x) { + if (x.hasOwnProperty(D)) { + const Y = x[D]; + qn(g, D, Y); } } } const H = { - xhr: p, + xhr: g, target: c, requestConfig: C, etc: i, boosted: _, - select: X, + select: F, pathInfo: { requestPath: n, finalRequestPath: R, @@ -3023,68 +3055,69 @@ var htmx = (function () { anchor: O, }, }; - p.onload = function () { + g.onload = function () { try { - const t = Hn(r); - H.pathInfo.responsePath = On(p); + const t = Nn(r); + H.pathInfo.responsePath = An(g); M(r, H); if (H.keepIndicators !== true) { - Qt(T, q); + rn(T, q); } - he(r, "htmx:afterRequest", H); - he(r, "htmx:afterOnLoad", H); - if (!le(r)) { + ae(r, "htmx:afterRequest", H); + ae(r, "htmx:afterOnLoad", H); + if (!se(r)) { let e = null; while (t.length > 0 && e == null) { const n = t.shift(); - if (le(n)) { + if (se(n)) { e = n; } } if (e) { - he(e, "htmx:afterRequest", H); - he(e, "htmx:afterOnLoad", H); + ae(e, "htmx:afterRequest", H); + ae(e, "htmx:afterOnLoad", H); } } - oe(s); - m(); + re(s); } catch (e) { - fe(r, "htmx:onLoadError", ce({ error: e }, H)); + fe(r, "htmx:onLoadError", le({ error: e }, H)); throw e; + } finally { + m(); } }; - p.onerror = function () { - Qt(T, q); + g.onerror = function () { + rn(T, q); fe(r, "htmx:afterRequest", H); fe(r, "htmx:sendError", H); - oe(l); + re(l); m(); }; - p.onabort = function () { - Qt(T, q); + g.onabort = function () { + rn(T, q); fe(r, "htmx:afterRequest", H); fe(r, "htmx:sendAbort", H); - oe(l); + re(l); m(); }; - p.ontimeout = function () { - Qt(T, q); + g.ontimeout = function () { + rn(T, q); fe(r, "htmx:afterRequest", H); fe(r, "htmx:timeout", H); - oe(l); + re(l); m(); }; - if (!he(r, "htmx:beforeRequest", H)) { - oe(s); + if (!ae(r, "htmx:beforeRequest", H)) { + re(s); m(); return e; } - var T = Zt(r); - var q = Yt(r); - se(["loadstart", "loadend", "progress", "abort"], function (t) { - se([p, p.upload], function (e) { + var T = tn(r); + var q = nn(r); + ie(["loadstart", "loadend", "progress", "abort"], function (t) { + ie([g, g.upload], function (e) { e.addEventListener(t, function (e) { - he(r, "htmx:xhr:" + t, { + ae(r, "htmx:xhr:" + t, { lengthComputable: e.lengthComputable, loaded: e.loaded, total: e.total, @@ -3092,22 +3125,22 @@ var htmx = (function () { }); }); }); - he(r, "htmx:beforeSend", H); - const J = E ? null : mn(p, r, w); - p.send(J); + ae(r, "htmx:beforeSend", H); + const J = E ? null : wn(g, r, w); + g.send(J); return e; } - function Nn(e, t) { + function Mn(e, t) { const n = t.xhr; let r = null; let o = null; - if (R(n, /HX-Push:/i)) { + if (H(n, /HX-Push:/i)) { r = n.getResponseHeader("HX-Push"); o = "push"; - } else if (R(n, /HX-Push-Url:/i)) { + } else if (H(n, /HX-Push-Url:/i)) { r = n.getResponseHeader("HX-Push-Url"); o = "push"; - } else if (R(n, /HX-Replace-Url:/i)) { + } else if (H(n, /HX-Replace-Url:/i)) { r = n.getResponseHeader("HX-Replace-Url"); o = "replace"; } @@ -3120,264 +3153,228 @@ var htmx = (function () { } const i = t.pathInfo.finalRequestPath; const s = t.pathInfo.responsePath; - const l = re(e, "hx-push-url"); - const c = re(e, "hx-replace-url"); - const u = ie(e).boosted; - let a = null; + const l = ne(e, "hx-push-url"); + const c = ne(e, "hx-replace-url"); + const u = oe(e).boosted; let f = null; + let a = null; if (l) { - a = "push"; - f = l; + f = "push"; + a = l; } else if (c) { - a = "replace"; - f = c; + f = "replace"; + a = c; } else if (u) { - a = "push"; - f = s || i; + f = "push"; + a = s || i; } - if (f) { - if (f === "false") { + if (a) { + if (a === "false") { return {}; } - if (f === "true") { - f = s || i; + if (a === "true") { + a = s || i; } - if (t.pathInfo.anchor && f.indexOf("#") === -1) { - f = f + "#" + t.pathInfo.anchor; + if (t.pathInfo.anchor && a.indexOf("#") === -1) { + a = a + "#" + t.pathInfo.anchor; } - return { type: a, path: f }; + return { type: f, path: a }; } else { return {}; } } - function In(e, t) { + function Fn(e, t) { var n = new RegExp(e.code); return n.test(t.toString(10)); } - function Pn(e) { + function Xn(e) { for (var t = 0; t < Q.config.responseHandling.length; t++) { var n = Q.config.responseHandling[t]; - if (In(n, e.status)) { + if (Fn(n, e.status)) { return n; } } return { swap: false }; } - function kn(e) { + function Bn(e) { if (e) { - const t = u("title"); + const t = f("title"); if (t) { - t.innerHTML = e; + t.textContent = e; } else { window.document.title = e; } } } - function Dn(o, i) { - const s = i.xhr; - let l = i.target; - const e = i.etc; - const c = i.select; - if (!he(o, "htmx:beforeOnLoad", i)) return; - if (R(s, /HX-Trigger:/i)) { - Je(s, "HX-Trigger", o); + function Un(e, t) { + if (t === "this") { + return e; } - if (R(s, /HX-Location:/i)) { - zt(); - let e = s.getResponseHeader("HX-Location"); - var t; + const n = ce(ue(e, t)); + if (n == null) { + fe(e, "htmx:targetError", { target: t }); + throw new Error(`Invalid re-target ${t}`); + } + return n; + } + function jn(t, e) { + const n = e.xhr; + let r = e.target; + const o = e.etc; + const i = e.select; + if (!ae(t, "htmx:beforeOnLoad", e)) return; + if (H(n, /HX-Trigger:/i)) { + Je(n, "HX-Trigger", t); + } + if (H(n, /HX-Location:/i)) { + Gt(); + let e = n.getResponseHeader("HX-Location"); + var s; if (e.indexOf("{") === 0) { - t = S(e); - e = t.path; - delete t.path; + s = v(e); + e = s.path; + delete s.path; } - Rn("get", e, t).then(function () { - $t(e); + Ln("get", e, s).then(function () { + Wt(e); }); return; } - const n = - R(s, /HX-Refresh:/i) && s.getResponseHeader("HX-Refresh") === "true"; - if (R(s, /HX-Redirect:/i)) { - i.keepIndicators = true; - location.href = s.getResponseHeader("HX-Redirect"); - n && location.reload(); + const l = + H(n, /HX-Refresh:/i) && n.getResponseHeader("HX-Refresh") === "true"; + if (H(n, /HX-Redirect:/i)) { + e.keepIndicators = true; + Q.location.href = n.getResponseHeader("HX-Redirect"); + l && Q.location.reload(); return; } - if (n) { - i.keepIndicators = true; - location.reload(); + if (l) { + e.keepIndicators = true; + Q.location.reload(); return; } - if (R(s, /HX-Retarget:/i)) { - if (s.getResponseHeader("HX-Retarget") === "this") { - i.target = o; - } else { - i.target = ue(ae(o, s.getResponseHeader("HX-Retarget"))); - } - } - const u = Nn(o, i); - const r = Pn(s); - const a = r.swap; - let f = !!r.error; - let h = Q.config.ignoreTitle || r.ignoreTitle; - let d = r.select; - if (r.target) { - i.target = ue(ae(o, r.target)); + const c = Mn(t, e); + const u = Xn(n); + const f = u.swap; + let a = !!u.error; + let h = Q.config.ignoreTitle || u.ignoreTitle; + let d = u.select; + if (u.target) { + e.target = Un(t, u.target); } - var g = e.swapOverride; - if (g == null && r.swapOverride) { - g = r.swapOverride; + var p = o.swapOverride; + if (p == null && u.swapOverride) { + p = u.swapOverride; } - if (R(s, /HX-Retarget:/i)) { - if (s.getResponseHeader("HX-Retarget") === "this") { - i.target = o; - } else { - i.target = ue(ae(o, s.getResponseHeader("HX-Retarget"))); - } + if (H(n, /HX-Retarget:/i)) { + e.target = Un(t, n.getResponseHeader("HX-Retarget")); } - if (R(s, /HX-Reswap:/i)) { - g = s.getResponseHeader("HX-Reswap"); + if (H(n, /HX-Reswap:/i)) { + p = n.getResponseHeader("HX-Reswap"); } - var p = s.response; - var m = ce( + var g = n.response; + var m = le( { - shouldSwap: a, - serverResponse: p, - isError: f, + shouldSwap: f, + serverResponse: g, + isError: a, ignoreTitle: h, selectOverride: d, - swapOverride: g, + swapOverride: p, }, - i, + e, ); - if (r.event && !he(l, r.event, m)) return; - if (!he(l, "htmx:beforeSwap", m)) return; - l = m.target; - p = m.serverResponse; - f = m.isError; + if (u.event && !ae(r, u.event, m)) return; + if (!ae(r, "htmx:beforeSwap", m)) return; + r = m.target; + g = m.serverResponse; + a = m.isError; h = m.ignoreTitle; d = m.selectOverride; - g = m.swapOverride; - i.target = l; - i.failed = f; - i.successful = !f; + p = m.swapOverride; + e.target = r; + e.failed = a; + e.successful = !a; if (m.shouldSwap) { - if (s.status === 286) { - lt(o); + if (n.status === 286) { + lt(t); } - Ft(o, function (e) { - p = e.transformResponse(p, s, o); + jt(t, function (e) { + g = e.transformResponse(g, n, t); }); - if (u.type) { - zt(); + if (c.type) { + Gt(); } - var x = gn(o, g); - if (!x.hasOwnProperty("ignoreTitle")) { - x.ignoreTitle = h; + var y = bn(t, p); + if (!y.hasOwnProperty("ignoreTitle")) { + y.ignoreTitle = h; } - l.classList.add(Q.config.swappingClass); - let n = null; - let r = null; - if (c) { - d = c; - } - if (R(s, /HX-Reselect:/i)) { - d = s.getResponseHeader("HX-Reselect"); - } - const y = re(o, "hx-select-oob"); - const b = re(o, "hx-select"); - let e = function () { - try { - if (u.type) { - he(ne().body, "htmx:beforeHistoryUpdate", ce({ history: u }, i)); - if (u.type === "push") { - $t(u.path); - he(ne().body, "htmx:pushedIntoHistory", { path: u.path }); + r.classList.add(Q.config.swappingClass); + if (i) { + d = i; + } + if (H(n, /HX-Reselect:/i)) { + d = n.getResponseHeader("HX-Reselect"); + } + const x = ne(t, "hx-select-oob"); + const b = ne(t, "hx-select"); + $e(r, g, y, { + select: d === "unset" ? null : d || b, + selectOOB: x, + eventInfo: e, + anchor: e.pathInfo.anchor, + contextElement: t, + afterSwapCallback: function () { + if (H(n, /HX-Trigger-After-Swap:/i)) { + let e = t; + if (!se(t)) { + e = te().body; + } + Je(n, "HX-Trigger-After-Swap", e); + } + }, + afterSettleCallback: function () { + if (H(n, /HX-Trigger-After-Settle:/i)) { + let e = t; + if (!se(t)) { + e = te().body; + } + Je(n, "HX-Trigger-After-Settle", e); + } + }, + beforeSwapCallback: function () { + if (c.type) { + ae(te().body, "htmx:beforeHistoryUpdate", le({ history: c }, e)); + if (c.type === "push") { + Wt(c.path); + ae(te().body, "htmx:pushedIntoHistory", { path: c.path }); } else { - Jt(u.path); - he(ne().body, "htmx:replacedInHistory", { path: u.path }); + Zt(c.path); + ae(te().body, "htmx:replacedInHistory", { path: c.path }); } } - $e(l, p, x, { - select: d || b, - selectOOB: y, - eventInfo: i, - anchor: i.pathInfo.anchor, - contextElement: o, - afterSwapCallback: function () { - if (R(s, /HX-Trigger-After-Swap:/i)) { - let e = o; - if (!le(o)) { - e = ne().body; - } - Je(s, "HX-Trigger-After-Swap", e); - } - }, - afterSettleCallback: function () { - if (R(s, /HX-Trigger-After-Settle:/i)) { - let e = o; - if (!le(o)) { - e = ne().body; - } - Je(s, "HX-Trigger-After-Settle", e); - } - oe(n); - }, - }); - } catch (e) { - fe(o, "htmx:swapError", i); - oe(r); - throw e; - } - }; - let t = Q.config.globalViewTransitions; - if (x.hasOwnProperty("transition")) { - t = x.transition; - } - if ( - t && - he(o, "htmx:beforeTransition", i) && - typeof Promise !== "undefined" && - document.startViewTransition - ) { - const v = new Promise(function (e, t) { - n = e; - r = t; - }); - const w = e; - e = function () { - document.startViewTransition(function () { - w(); - return v; - }); - }; - } - if (x.swapDelay > 0) { - E().setTimeout(e, x.swapDelay); - } else { - e(); - } + }, + }); } - if (f) { + if (a) { fe( - o, + t, "htmx:responseError", - ce( + le( { error: "Response Status Error Code " + - s.status + + n.status + " from " + - i.pathInfo.requestPath, + e.pathInfo.requestPath, }, - i, + e, ), ); } } - const Mn = {}; - function Xn() { + const Vn = {}; + function _n() { return { init: function (e) { return null; @@ -3402,16 +3399,16 @@ var htmx = (function () { }, }; } - function Fn(e, t) { + function zn(e, t) { if (t.init) { t.init(n); } - Mn[e] = ce(Xn(), t); + Vn[e] = le(_n(), t); } - function Bn(e) { - delete Mn[e]; + function $n(e) { + delete Vn[e]; } - function Un(e, n, r) { + function Jn(e, n, r) { if (n == undefined) { n = []; } @@ -3421,41 +3418,41 @@ var htmx = (function () { if (r == undefined) { r = []; } - const t = te(e, "hx-ext"); + const t = a(e, "hx-ext"); if (t) { - se(t.split(","), function (e) { + ie(t.split(","), function (e) { e = e.replace(/ /g, ""); if (e.slice(0, 7) == "ignore:") { r.push(e.slice(7)); return; } if (r.indexOf(e) < 0) { - const t = Mn[e]; + const t = Vn[e]; if (t && n.indexOf(t) < 0) { n.push(t); } } }); } - return Un(ue(c(e)), n, r); + return Jn(ce(u(e)), n, r); } - var jn = false; - ne().addEventListener("DOMContentLoaded", function () { - jn = true; + var Kn = false; + te().addEventListener("DOMContentLoaded", function () { + Kn = true; }); - function Vn(e) { - if (jn || ne().readyState === "complete") { + function Gn(e) { + if (Kn || te().readyState === "complete") { e(); } else { - ne().addEventListener("DOMContentLoaded", e); + te().addEventListener("DOMContentLoaded", e); } } - function _n() { + function Wn() { if (Q.config.includeIndicatorStyles !== false) { const e = Q.config.inlineStyleNonce ? ` nonce="${Q.config.inlineStyleNonce}"` : ""; - ne().head.insertAdjacentHTML( + te().head.insertAdjacentHTML( "beforeend", " /dev/null; then \ + read -p "Go's 'sqlc' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ + if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ + go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest; \ + if [ ! -x "$$(command -v sqlc)" ]; then \ + echo "sqlc installation failed. Exiting..."; \ + exit 1; \ + fi; \ + else \ + echo "You chose not to install sqlc. Exiting..."; \ + exit 1; \ + fi; \ + fi +{{- else }} +sqlc-install: + @powershell -ExecutionPolicy Bypass -Command "if (Get-Command sqlc -ErrorAction SilentlyContinue) { \ + ; \ + } else { \ + Write-Output 'Installing sqlc...'; \ + go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest; \ + if (-not (Get-Command sqlc -ErrorAction SilentlyContinue)) { \ + Write-Output 'sqlc installation failed. Exiting...'; \ + exit 1; \ + } else { \ + Write-Output 'sqlc installed successfully.'; \ + } \ + }" +{{- end }} +{{- end }} +build:{{- if and .AdvancedOptions.tailwind (not .AdvancedOptions.react) }} tailwind-install{{- end }}{{- if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }} templ-install{{- end }}{{- if .AdvancedOptions.sqlc}} sqlc-install {{- end }} @echo "Building..." {{ if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }}@templ generate{{- end }} {{ if and .AdvancedOptions.tailwind (not .AdvancedOptions.react) }}@{{ if .OSCheck.UnixBased }}./tailwindcss{{ else }}.\tailwindcss.exe{{ end }} -i cmd/web/styles/input.css -o cmd/web/assets/css/output.css{{ end }} + {{- if .AdvancedOptions.sqlc }}@sqlc generate {{- end}} {{ if .OSCheck.UnixBased }}@{{- if and (.AdvancedOptions.docker) (eq .DBDriver "sqlite") }}CGO_ENABLED=1 GOOS=linux {{ end }}go build -o main cmd/api/main.go{{- else }}@go build -o main.exe cmd/api/main.go{{- end }} # Run the application @@ -138,4 +170,4 @@ watch: }" {{- end }} -.PHONY: all build run test clean watch{{- if and (not .AdvancedOptions.react) .AdvancedOptions.tailwind }} tailwind-install{{- end }}{{- if and (ne .DBDriver "none") (ne .DBDriver "sqlite") }} docker-run docker-down itest{{- end }}{{- if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }} templ-install{{- end }} +.PHONY: all build run test clean watch{{- if and (not .AdvancedOptions.react) .AdvancedOptions.tailwind }} tailwind-install{{- end }}{{- if and (ne .DBDriver "none") (ne .DBDriver "sqlite") }} docker-run docker-down itest{{- end }}{{- if and (or .AdvancedOptions.htmx .AdvancedOptions.tailwind) (not .AdvancedOptions.react) }} templ-install{{- end }}{{- if .AdvancedOptions.sql }} sqlc-generate {{- end}} diff --git a/cmd/utils/utils.go b/cmd/utils/utils.go index 72c71456c..6266b62d0 100644 --- a/cmd/utils/utils.go +++ b/cmd/utils/utils.go @@ -5,10 +5,12 @@ package utils import ( "bytes" "fmt" + "log" "os/exec" "regexp" "strings" + "github.com/spf13/cobra" "github.com/spf13/pflag" ) @@ -47,6 +49,16 @@ func NonInteractiveCommand(use string, flagSet *pflag.FlagSet) string { return nonInteractiveCommand } +func RegisterStaticCompletions(cmd *cobra.Command, flag string, options []string) { + err := cmd.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return options, cobra.ShellCompDirectiveNoFileComp + }) + + if err != nil { + log.Printf("warning: could not register completion for --%s: %v", flag, err) + } +} + // ExecuteCmd provides a shorthand way to run a shell command func ExecuteCmd(name string, args []string, dir string) error { command := exec.Command(name, args...) diff --git a/docs/docs/advanced-flag/advanced-flag.md b/docs/docs/advanced-flag/advanced-flag.md index 124ef6b91..cfc6307cf 100644 --- a/docs/docs/advanced-flag/advanced-flag.md +++ b/docs/docs/advanced-flag/advanced-flag.md @@ -2,6 +2,7 @@ The `--advanced` flag in Blueprint serves as a switch to enable additional features during project creation. It is applied with the `create` command and unlocks the following features: + - **HTMX Support using Templ:** Enables the integration of HTMX support for dynamic web pages using Templ. @@ -20,6 +21,8 @@ Docker configuration for go project. - **React:** Frontend written in TypeScript, including an example fetch request to the backend. +- **SQLC:** +Generates SQL queries and typesafe code for database interactions using SQLC. To utilize the `--advanced` flag, use the following command: diff --git a/docs/docs/advanced-flag/docker.md b/docs/docs/advanced-flag/docker.md index 3f250ef54..75959d490 100644 --- a/docs/docs/advanced-flag/docker.md +++ b/docs/docs/advanced-flag/docker.md @@ -4,9 +4,9 @@ The Dockerfile includes a two-stage build, and the final config depends on the u ## Dockerfile ```dockerfile -FROM golang:1.23-alpine AS build +FROM golang:1.24.4-alpine AS build -RUN apk add --no-cache curl +RUN apk add --no-cache curl libstdc++ libgcc WORKDIR /app @@ -17,7 +17,7 @@ COPY . . RUN go install github.com/a-h/templ/cmd/templ@latest && \ templ generate && \ - curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss && \ + curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64-musl -o tailwindcss && \ chmod +x tailwindcss && \ ./tailwindcss -i cmd/web/styles/input.css -o cmd/web/assets/css/output.css @@ -33,7 +33,7 @@ CMD ["./main"] Docker config if React flag is used: ```dockerfile -FROM golang:1.23-alpine AS build +FROM golang:1.24.4-alpine AS build WORKDIR /app diff --git a/docs/docs/advanced-flag/react-vite.md b/docs/docs/advanced-flag/react-vite.md index 01de8afe8..ae29ac221 100644 --- a/docs/docs/advanced-flag/react-vite.md +++ b/docs/docs/advanced-flag/react-vite.md @@ -7,14 +7,14 @@ The React advanced flag can be combined with the Tailwind flag for enhanced styl ```bash / (Root) ├── frontend/ # React advanced flag. Excludes HTMX. -│ ├── .env # Frontend environment configuration +│ ├── .env # Frontend environment configuration. │ ├── node_modules/ # Node dependencies. │ ├── public/ │ │ ├── index.html │ │ └── favicon.ico │ ├── src/ # React source files. │ │ ├── App.tsx # Main React component. -│ │ ├── assets/ # React assets directory +│ │ ├── assets/ # React assets directory. │ │ │ └── logo.svg │ │ ├── components/ # React components directory. │ │ │ ├── Header.tsx @@ -87,7 +87,7 @@ make docker-run ### Dockerfile ```dockerfile -FROM golang:1.23-alpine AS build +FROM golang:1.24.4-alpine AS build WORKDIR /app diff --git a/docs/docs/advanced-flag/sqlc.md b/docs/docs/advanced-flag/sqlc.md new file mode 100644 index 000000000..69c93552d --- /dev/null +++ b/docs/docs/advanced-flag/sqlc.md @@ -0,0 +1,101 @@ +When SQLC support is enabled, the project includes a configuration file and example SQL files. Running `sqlc generate` produces type-safe Go code for executing your queries using the standard `database/sql` interface by default. However, SQLC is also compatible with `pgx` v4 and v5. + +SQLC supports PostgreSQL, MySQL, and SQLite. + +## Project Structure + +The generated project will follow this structure: + +```bash +/ (Root) +├── cmd/ +│ └── api/ +│ └── main.go +├── internal/ +│ ├── database/ +│ │ ├── database.go +│ │ ├── database_test.go +│ │ ├── repository/ +│ │ │ ├── db.go +│ │ │ ├── models.go +│ │ │ ├── querier.go +│ │ │ └── query.sql.go +│ │ └── sql/ +│ │ ├── query.sql +│ │ └── schema.sql +│ └── server/ +│ ├── routes.go +│ ├── routes_test.go +│ └── server.go +├── go.mod +├── go.sum +├── Makefile +├── README.md +└── sqlc.yaml +``` + +## SQLC Configuration + +The `sqlc.yaml` configuration file is automatically created at the root of the project. It defines how SQLC generates Go code from your SQL schema and query files. + +```yaml +version: "2" +sql: + - engine: "postgresql" + queries: "internal/database/sql/query.sql" + schema: "internal/database/sql/schema.sql" + gen: + go: + package: "repository" + out: "internal/database/repository" + emit_json_tags: true + emit_prepared_queries: false + emit_interface: true + emit_empty_slices: true +``` + +## Example SQL Files + +### Schema + +```sql +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + created_at TIMESTAMP DEFAULT NOW() +); +``` + +### Queries + +```sql +-- name: GetUserByID :one +SELECT id, name, email FROM users WHERE id = $1; + +-- name: ListUsers :many +SELECT * FROM users ORDER BY created_at DESC; +``` + +## Makefile Integration + +The Makefile includes entries for installing SQLC and generating code. + + +```bash +sqlc-install: + # Installation logic goes here + +build: sqlc-install + @echo "Building..." + @sqlc generate + @go build -o main cmd/api/main.go +``` + +## Use SQLC in your project + +By default, the project includes SQL schema and query files. +To customize them: + +1. Modify the files under `internal/database/sql/`. +2. Run `sqlc generate` to regenerate the Go code reflecting your changes. diff --git a/docs/docs/advanced-flag/tailwind.md b/docs/docs/advanced-flag/tailwind.md index 4b869b090..56c9881b7 100644 --- a/docs/docs/advanced-flag/tailwind.md +++ b/docs/docs/advanced-flag/tailwind.md @@ -36,7 +36,7 @@ The project tree would look like this: ## Standalone Tailwind CLI -The The idea is to avoid using Node.js and npm to build output.css. +The idea is to avoid using Node.js and npm to build output.css. The Makefile will have entries for downloading and compiling CSS. It will automatically detect the OS and download the latest release from the [official repository](https://github.com/tailwindlabs/tailwindcss/releases). diff --git a/docs/docs/advanced-flag/websocket.md b/docs/docs/advanced-flag/websocket.md index c7bea3ad6..aaafb4252 100644 --- a/docs/docs/advanced-flag/websocket.md +++ b/docs/docs/advanced-flag/websocket.md @@ -1,4 +1,4 @@ -A `/websocket` endpoint is added in `routes.go` to facilitate websocket connections. Upon accessing this endpoint, the server establishes a websocket connection and begins transmitting timestamp messages at 2-second intervals. WS is utilized across all Go-blueprint supported frameworks. This simple implementation showcases how flexible project is. +A `/websocket` endpoint is added in `routes.go` to facilitate websocket connections. Upon accessing this endpoint, the server establishes a websocket connection and begins transmitting timestamp messages at 2-second intervals. WS is utilized across all Go-blueprint supported frameworks. This simple implementation showcases how flexible a project is. ### Code Implementation diff --git a/docs/docs/blueprint-core/db-drivers.md b/docs/docs/blueprint-core/db-drivers.md index f34c72d0a..e4d4b62ed 100644 --- a/docs/docs/blueprint-core/db-drivers.md +++ b/docs/docs/blueprint-core/db-drivers.md @@ -4,7 +4,7 @@ To extend the project with database functionality, users can choose from a varie 2. [Mysql](https://github.com/go-sql-driver/mysql): Enables seamless integration with MySQL databases. 3. [Postgres](https://github.com/jackc/pgx/): Facilitates connectivity to PostgreSQL databases. 4. [Redis](https://github.com/redis/go-redis): Provides tools for connecting and interacting with Redis. -5. [Sqlite](https://github.com/mattn/go-sqlite3): Suitable for projects requiring a lightweight, self-contained database. and interacting with Redis +5. [Sqlite](https://github.com/mattn/go-sqlite3): Suitable for projects requiring a lightweight, self-contained database. 6. [ScyllaDB](https://github.com/scylladb/gocql): Facilitates connectivity to ScyllaDB databases. ## Updated Project Structure @@ -36,7 +36,7 @@ Users can select the desired database driver based on their project's specific n ## Integration Tests for Database Operations -For all the database drivers but the `Sqlite`, integration tests are automatically generated to ensure that the database connection is working correctly. It uses [Testcontainers for Go](https://golang.testcontainers.org/) to spin up a containerized instance of the database server, run the tests, and then tear down the container. +For all the database drivers but `Sqlite`, integration tests are automatically generated to ensure that the database connection is working correctly. It uses [Testcontainers for Go](https://golang.testcontainers.org/) to spin up a containerized instance of the database server, run the tests, and then tear down the container. [Testcontainers for Go](https://golang.testcontainers.org/) is a Go package that makes it simple to create and clean up container-based dependencies for automated integration/smoke tests. The clean, easy-to-use API enables developers to programmatically define containers that should be run as part of a test and clean up those resources when the test is done. @@ -59,7 +59,7 @@ Go to the `internal/database` directory and run the following command: go test -v ``` -or just run the following command from the root directory: +Or, just run the following command from the root directory: ```bash make itest diff --git a/docs/docs/blueprint-core/frameworks.md b/docs/docs/blueprint-core/frameworks.md index 00aa84df6..4d86e82b1 100644 --- a/docs/docs/blueprint-core/frameworks.md +++ b/docs/docs/blueprint-core/frameworks.md @@ -1,4 +1,4 @@ -Created project can utilizes several Go web frameworks to handle HTTP routing and server functionality. The chosen frameworks are: +Created projects can utilize several Go web frameworks to handle HTTP routing and server functionality. The chosen frameworks are: 1. [**Chi**](https://github.com/go-chi/chi): Lightweight and flexible router for building Go HTTP services. 2. [**Echo**](https://github.com/labstack/echo): High-performance, extensible, minimalist Go web framework. diff --git a/docs/docs/creating-project/makefile.md b/docs/docs/creating-project/makefile.md index 2717797af..112da2c40 100644 --- a/docs/docs/creating-project/makefile.md +++ b/docs/docs/creating-project/makefile.md @@ -8,6 +8,7 @@ Makefile is designed for building, running, and testing a Go project. It include The default target that builds and test the application by running the `build` and `test` target. + ***`templ-install`*** This target installs the Go-based templating tool, `templ`, if it is not already installed. It supports: @@ -23,6 +24,14 @@ This target downloads and sets up `tailwindcss`, depending on the user's operati - **macOS**: Downloads the macOS binary. - **Windows**: Uses PowerShell to download the Windows executable. +***`sqlc-install`*** + +This target installs the `sqlc` tool, which is used for generating Go code from SQL queries. It supports: + +- **Unix-based systems**: Prompts the user to install `sqlc` if it is not already installed. +- **Windows**: Uses PowerShell to check for and install `sqlc`. + + ***`build`*** Builds the Go application and generates assets with `templ` and `tailwind`, if the corresponding advanced options are enabled: diff --git a/docs/docs/creating-project/project-init.md b/docs/docs/creating-project/project-init.md index 9eae177c5..4cb9516e8 100644 --- a/docs/docs/creating-project/project-init.md +++ b/docs/docs/creating-project/project-init.md @@ -39,7 +39,7 @@ To recreate the project using the same configuration semi-interactively, use the ```bash go-blueprint create --name my-project --framework chi --driver mysql --git commit --advanced ``` -This approach opens interactive mode only for advanced features, which allow you to choose the one or combination of available features. +This approach opens interactive mode only for advanced features, which allows you to choose the one or combination of available features. ![AdvancedFlag](../public/blueprint_advanced.png) @@ -69,8 +69,12 @@ Docker: ```bash go-blueprint create --advanced --feature docker ``` +Sqlc: +```bash +go-blueprint create --advanced --feature sqlc +``` Or all features at once: ```bash -go-blueprint create --name my-project --framework chi --driver mysql --git commit --advanced --feature htmx --feature githubaction --feature websocket --feature tailwind --feature docker +go-blueprint create --name my-project --framework chi --driver mysql --git commit --advanced --feature htmx --feature githubaction --feature websocket --feature tailwind --feature docker --feature sqlc ``` diff --git a/docs/docs/endpoints-test/mongo.md b/docs/docs/endpoints-test/mongo.md index 15557f30c..1c81aa9c7 100644 --- a/docs/docs/endpoints-test/mongo.md +++ b/docs/docs/endpoints-test/mongo.md @@ -44,4 +44,4 @@ func (s *service) Health() map[string]string { ## Note -MongoDB does not support advanced health check functions like SQL databases or Redis. Implementation is basic, providing only a simple ping response to indicate if the server is reachable and DB connection healthy. +MongoDB does not support advanced health check functions like SQL databases or Redis. The implementation is basic, providing only a simple ping response to indicate if the server is reachable and DB connection healthy. diff --git a/docs/docs/index.md b/docs/docs/index.md index 3219be683..1e0d44f2a 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -33,8 +33,8 @@ Here's an overview of the project structure created by Go Blueprint when all opt │ ├── api/ │ │ └── main.go # Main file for starting the server. │ └── web/ -│ ├── styles/ # only for generating css will not be served public -│ │ └── input.css # Tailwind input file for compiling output.css with CLI when HTMX is used +│ ├── styles/ # Only for generating css will not be served public. +│ │ └── input.css # Tailwind input file for compiling output.css with CLI when HTMX is used. │ ├── assets/ │ │ ├── css/ │ │ │ └── output.css # Generated CSS file. @@ -53,7 +53,7 @@ Here's an overview of the project structure created by Go Blueprint when all opt │ │ └── favicon.ico │ ├── src/ # React source files. │ │ ├── App.tsx # Main React component. -│ │ ├── assets/ # React assets directory +│ │ ├── assets/ # React assets directory. │ │ │ └── logo.svg │ │ ├── components/ # React components directory. │ │ │ ├── Header.tsx diff --git a/docs/docs/installation.md b/docs/docs/installation.md index 852a103f6..80b97a5e4 100644 --- a/docs/docs/installation.md +++ b/docs/docs/installation.md @@ -7,7 +7,7 @@ Go-Blueprint provides a convenient CLI tool to effortlessly set up your Go proje ## Binary Installation -To install the Go-Blueprint CLI tool as a binary, Run the following command: +To install the Go-Blueprint CLI tool as a binary, run the following command: ```sh go install github.com/melkeydev/go-blueprint@latest @@ -15,7 +15,7 @@ go install github.com/melkeydev/go-blueprint@latest This command installs the Go-Blueprint binary, automatically binding it to your `$GOPATH`. -> if you’re using Zsh, you’ll need to add it manually to `~/.zshrc`. +> If you’re using Zsh, you’ll need to add it manually to `~/.zshrc`. > After running the installation command, you need to update your `PATH` environment variable. To do this, you need to find out the correct `GOPATH` for your system. You can do this by running the following command: > Check your `GOPATH` @@ -36,6 +36,26 @@ This command installs the Go-Blueprint binary, automatically binding it to your > source ~/.zshrc > ``` +## NPM Install + +If you prefer using Node.js package manager, you can install Go-Blueprint via NPM. This method is convenient for developers who are already working in JavaScript/Node.js environments and want to integrate Go-Blueprint into their existing workflow. + +```bash +npm install -g @melkeydev/go-blueprint +``` + +The `-g` flag installs Go-Blueprint globally, making it accessible from any directory on your system. + +## Homebrew Install + +For macOS and Linux users, Homebrew provides a simple way to install Go-Blueprint. Homebrew automatically handles dependencies and keeps the tool updated through its package management system. + +```bash +brew install go-blueprint +``` + +After installation via Homebrew, Go-Blueprint will be automatically added to your PATH, making it immediately available in your terminal. + ## Building and Installing from Source If you prefer to build and install Go-Blueprint directly from the source code, you can follow these steps: diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index b9ece5be4..76f8a5e62 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -18,7 +18,7 @@ theme: - navigation.sections - navigation.footer - toc.flow - palette: + palette: - scheme: default toggle: icon: material/brightness-7 @@ -33,44 +33,45 @@ nav: - Installation: installation.md - Blueprint UI: blueprint-ui.md - Project creation & default config: - - Project init: creating-project/project-init.md - - Makefile: creating-project/makefile.md - - Air: creating-project/air.md + - Project init: creating-project/project-init.md + - Makefile: creating-project/makefile.md + - Air: creating-project/air.md - Blueprint Core: - - Frameworks: blueprint-core/frameworks.md - - DB Drivers: blueprint-core/db-drivers.md + - Frameworks: blueprint-core/frameworks.md + - DB Drivers: blueprint-core/db-drivers.md - Advanced Flag: - - AF Usage: advanced-flag/advanced-flag.md - - HTMX and Templ: advanced-flag/htmx-templ.md - - Tailwind CSS: advanced-flag/tailwind.md - - GoReleaser & GoTest CI: advanced-flag/goreleaser.md - - Websocket: advanced-flag/websocket.md - - Docker: advanced-flag/docker.md - - React & Vite (TypeScript): advanced-flag/react-vite.md - - Testing endpoints: - - Server: endpoints-test/server.md - - DB Health Endpoints: - - SQL DBs: endpoints-test/sql.md - - Redis: endpoints-test/redis.md - - MongoDB: endpoints-test/mongo.md - - ScyllaDB: endpoints-test/scylladb.md - - Websocket: endpoints-test/websocket.md - - Web Endpoint: endpoints-test/web.md + - AF Usage: advanced-flag/advanced-flag.md + - HTMX and Templ: advanced-flag/htmx-templ.md + - Tailwind CSS: advanced-flag/tailwind.md + - GoReleaser & GoTest CI: advanced-flag/goreleaser.md + - Websocket: advanced-flag/websocket.md + - Docker: advanced-flag/docker.md + - React & Vite (TypeScript): advanced-flag/react-vite.md + - SQLC: advanced-flag/sqlc.md + - Testing endpoints: + - Server: endpoints-test/server.md + - DB Health Endpoints: + - SQL DBs: endpoints-test/sql.md + - Redis: endpoints-test/redis.md + - MongoDB: endpoints-test/mongo.md + - ScyllaDB: endpoints-test/scylladb.md + - Websocket: endpoints-test/websocket.md + - Web Endpoint: endpoints-test/web.md extra: - social: - - icon: fontawesome/brands/discord - link: https://discord.com/invite/HHZMSCu - name: Discord - - icon: fontawesome/brands/twitch - link: https://www.twitch.tv/melkey - name: Twitch - - icon: fontawesome/brands/youtube - link: https://www.youtube.com/@MelkeyDev - name: YouTube - - icon: fontawesome/brands/twitter - link: https://x.com/MelkeyDev - name: Twitter - generator: false + social: + - icon: fontawesome/brands/discord + link: https://discord.com/invite/HHZMSCu + name: Discord + - icon: fontawesome/brands/twitch + link: https://www.twitch.tv/melkey + name: Twitch + - icon: fontawesome/brands/youtube + link: https://www.youtube.com/@MelkeyDev + name: YouTube + - icon: fontawesome/brands/twitter + link: https://x.com/MelkeyDev + name: Twitter + generator: false copyright: Copyright © 2025 Melkey diff --git a/go.mod b/go.mod index 88501fc45..200962c44 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/melkeydev/go-blueprint -go 1.22.4 +go 1.23.0 require ( github.com/charmbracelet/bubbles v0.16.1 diff --git a/scripts/create-npm-packages.sh b/scripts/create-npm-packages.sh new file mode 100644 index 000000000..04d530435 --- /dev/null +++ b/scripts/create-npm-packages.sh @@ -0,0 +1,240 @@ +#!/bin/bash + +set -euo pipefail + +VERSION="$1" +PACKAGE_NAME="@melkeydev/go-blueprint" +MAIN_PACKAGE_DIR="npm-package" +PLATFORM_PACKAGES_DIR="platform-packages" + +rm -rf "$MAIN_PACKAGE_DIR" "$PLATFORM_PACKAGES_DIR" + +mkdir -p "$MAIN_PACKAGE_DIR/bin" "$PLATFORM_PACKAGES_DIR" + +declare -A PLATFORM_MAP=( + ["go-blueprint_${VERSION}_Darwin_all"]="darwin-x64,darwin-arm64" + ["go-blueprint_${VERSION}_Linux_x86_64"]="linux-x64" + ["go-blueprint_${VERSION}_Linux_arm64"]="linux-arm64" + ["go-blueprint_${VERSION}_Windows_x86_64"]="win32-x64" + ["go-blueprint_${VERSION}_Windows_arm64"]="win32-arm64" +) + +declare -A OS_MAP=( + ["darwin-x64"]="darwin" + ["darwin-arm64"]="darwin" + ["linux-x64"]="linux" + ["linux-arm64"]="linux" + ["win32-x64"]="win32" + ["win32-arm64"]="win32" +) + +declare -A CPU_MAP=( + ["darwin-x64"]="x64" + ["darwin-arm64"]="arm64" + ["linux-x64"]="x64" + ["linux-arm64"]="arm64" + ["win32-x64"]="x64" + ["win32-arm64"]="arm64" +) + +OPTIONAL_DEPS="" +for archive in dist/*.tar.gz dist/*.zip; do + if [ -f "$archive" ]; then + archive_name=$(basename "$archive") + archive_name="${archive_name%.tar.gz}" + archive_name="${archive_name%.zip}" + + platform_keys="${PLATFORM_MAP[$archive_name]:-}" + + if [ -n "$platform_keys" ]; then + echo "Processing $archive for platforms: $platform_keys" + + IFS=',' read -ra PLATFORM_ARRAY <<< "$platform_keys" + for platform_key in "${PLATFORM_ARRAY[@]}"; do + platform_key=$(echo "$platform_key" | xargs) + + echo " Creating package for platform: $platform_key" + + platform_package_dir="$PLATFORM_PACKAGES_DIR/go-blueprint-$platform_key" + mkdir -p "$platform_package_dir/bin" + + if [[ "$archive" == *.tar.gz ]]; then + tar -xzf "$archive" -C "$platform_package_dir/bin" + else + unzip -j "$archive" -d "$platform_package_dir/bin" + fi + + for doc_file in README.md README README.txt LICENSE LICENSE.md LICENSE.txt; do + if [ -f "$platform_package_dir/bin/$doc_file" ]; then + mv "$platform_package_dir/bin/$doc_file" "$platform_package_dir/" + fi + done + + ls -l "$platform_package_dir/bin" + chmod +x "$platform_package_dir/bin/"* + + os_value="${OS_MAP[$platform_key]}" + cpu_value="${CPU_MAP[$platform_key]}" + + files_array='["bin/"]' + for doc_file in README.md README README.txt LICENSE LICENSE.md LICENSE.txt; do + if [ -f "$platform_package_dir/$doc_file" ]; then + files_array="${files_array%]}, \"$doc_file\"]" + fi + done + + binary_name="go-blueprint" + if [[ "$os_value" == "win32" ]]; then + binary_name="go-blueprint.exe" + fi + + cat > "$platform_package_dir/package.json" << EOF +{ + "name": "$PACKAGE_NAME-$platform_key", + "version": "$VERSION", + "description": "Platform-specific binary for $PACKAGE_NAME ($platform_key)", + "os": ["$os_value"], + "cpu": ["$cpu_value"], + "bin": { + "go-blueprint": "bin/$binary_name" + }, + "files": $files_array, + "repository": { + "type": "git", + "url": "https://github.com/Melkeydev/go-blueprint.git" + }, + "author": "Melkeydev", + "license": "MIT" +} +EOF + + if [ -n "$OPTIONAL_DEPS" ]; then + OPTIONAL_DEPS="$OPTIONAL_DEPS," + fi + OPTIONAL_DEPS="$OPTIONAL_DEPS\"$PACKAGE_NAME-$platform_key\": \"$VERSION\"" + done + fi + fi +done + +cat > "$MAIN_PACKAGE_DIR/bin/go-blueprint" << 'EOF' +#!/usr/bin/env node + +const { execFileSync } = require('child_process') + +const packageName = '@melkeydev/go-blueprint' + +const platformPackages = { + 'darwin-x64': `${packageName}-darwin-x64`, + 'darwin-arm64': `${packageName}-darwin-arm64`, + 'linux-x64': `${packageName}-linux-x64`, + 'linux-arm64': `${packageName}-linux-arm64`, + 'win32-x64': `${packageName}-win32-x64`, + 'win32-arm64': `${packageName}-win32-arm64` +} + +function getBinaryPath() { + const platformKey = `${process.platform}-${process.arch}` + const platformPackageName = platformPackages[platformKey] + + if (!platformPackageName) { + console.error(`Platform ${platformKey} is not supported!`) + process.exit(1) + } + + try { + const binaryName = process.platform === 'win32' ? 'go-blueprint.exe' : 'go-blueprint' + const packagePath = platformPackageName.replace('@', '').replace('/', '-') + return require.resolve(`${platformPackageName}/bin/${binaryName}`) + } catch (e) { + process.exit(1) + } +} + +try { + const binaryPath = getBinaryPath() + execFileSync(binaryPath, process.argv.slice(2), { stdio: 'inherit' }) +} catch (error) { + console.error('Failed to execute go-blueprint:', error.message) + process.exit(1) +} +EOF + +chmod +x "$MAIN_PACKAGE_DIR/bin/go-blueprint" + +cat > "$MAIN_PACKAGE_DIR/package.json" << EOF +{ + "name": "$PACKAGE_NAME", + "version": "$VERSION", + "description": "A CLI for scaffolding Go projects with modern tooling", + "main": "index.js", + "bin": { + "go-blueprint": "bin/go-blueprint" + }, + "optionalDependencies": { + $OPTIONAL_DEPS + }, + "keywords": ["go", "golang", "cli"], + "author": "Melkeydev", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/Melkeydev/go-blueprint.git" + }, + "homepage": "https://github.com/Melkeydev/go-blueprint", + "engines": { + "node": ">=14.0.0" + }, + "files": [ + "bin/", + "index.js", + "README.md" + ] +} +EOF + +cat > "$MAIN_PACKAGE_DIR/index.js" << 'EOF' +const { execFileSync } = require('child_process') +const path = require('path') + +const binaryName = process.platform === 'win32' ? 'go-blueprint.exe' : 'go-blueprint' + +const packageName = '@melkeydev/go-blueprint' + +const platformPackages = { + 'darwin-x64': `${packageName}-darwin-x64`, + 'darwin-arm64': `${packageName}-darwin-arm64`, + 'linux-x64': `${packageName}-linux-x64`, + 'linux-arm64': `${packageName}-linux-arm64`, + 'win32-x64': `${packageName}-win32-x64`, + 'win32-arm64': `${packageName}-win32-arm64` +} + +function getBinaryPath() { + const platformKey = `${process.platform}-${process.arch}` + const platformPackageName = platformPackages[platformKey] + + if (!platformPackageName) { + throw new Error(`Platform ${platformKey} is not supported!`) + } + + try { + return require.resolve(`${platformPackageName}/bin/${binaryName}`) + } catch (e) { + throw new Error(`Platform-specific package ${platformPackageName} not found.`) + } +} + +module.exports = { + getBinaryPath, + run: function(...args) { + const binaryPath = getBinaryPath() + return execFileSync(binaryPath, args, { stdio: 'inherit' }) + } +} +EOF + +first_platform_dir=$(ls -1d "$PLATFORM_PACKAGES_DIR"/* | head -1 2>/dev/null || echo "") +if [ -n "$first_platform_dir" ] && [ -f "$first_platform_dir/README.md" ]; then + cp "$first_platform_dir/README.md" "$MAIN_PACKAGE_DIR/" +fi \ No newline at end of file