commit e9680c4116e05173447c74b4f4a971164ba75918 Author: Lucien Cartier-Tilet Date: Wed Nov 19 11:46:15 2025 +0100 initial commit diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..1be34c9 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: + - master + - main + pull_request: + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + emacs-version: + - 26.3 + - 27.2 + - 28.1 + - snapshot + + steps: + - uses: actions/checkout@v2 + + - uses: jcs090218/setup-emacs@master + with: + version: ${{ matrix.emacs-version }} + + - uses: actions/setup-node@v2 + with: + node-version: '16' + + - uses: emacs-eask/setup-eask@master + with: + version: 'snapshot' + + - name: Run tests + run: + make ci diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a50232f --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# ignore these directories +/.git +/recipes + +# ignore generated files +*.elc + +# eask packages +.eask/ +dist/ + +# packaging +*-autoloads.el +*-pkg.el diff --git a/Eask b/Eask new file mode 100644 index 0000000..69d549f --- /dev/null +++ b/Eask @@ -0,0 +1,14 @@ +;; -*- mode: Cask -*- +(package "npm-transient" + "0.1.0" + "A transient menu for NPM projects") + +(website-url "https://labs.phundrak.com/phundrak/npm-transient.el") +(keywords "npm" "transient" "convenience" "project" "javascript" "typescript" "node" "yarn" "pnpm") + +(package-file "npm-transient.el") + +(source "gnu") + +(depends-on "emacs" "25.1") +(depends-on "transient" "0.3.7") diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..df47cfc --- /dev/null +++ b/Makefile @@ -0,0 +1,88 @@ +## +# Eask generated template Makefile +# +# File located in https://github.com/emacs-eask/template-elisp/blob/master/Makefile +## + +EMACS ?= emacs +EASK ?= eask + +.PHONY: clean package install compile test checkdoc lint + +# CI entry point +# +# You can add or remove any commands here +# +# (Option 1): Basic for beginner, only tests for package's installation +ci: clean package install compile +# (Option 2): Advanced for a high-quality package +#ci: clean package install compile checkdoc lint test + +# Build an package artefact, default to `dist` folder +# +# This is used to test if your package can be built correctly before the +# package installation. +package: + @echo "Packaging..." + $(EASK) package + +# Install package +# +# If your package is a single file package, you generally wouldn't need to +install: + @echo "Installing..." + $(EASK) install + +# Byte-compile package +# +# Compile all your package .el files to .elc +compile: + @echo "Compiling..." + $(EASK) compile + +# Run regression tests +# +# The default test is `ert`; but Eask also support other regression test! +# See https://emacs-eask.github.io/Getting-Started/Commands-and-options/#-linter +test: + @echo "Testing..." + $(EASK) install-deps --dev + $(EASK) test ert ./test/*.el + +# Run checkdoc +# +# See https://www.emacswiki.org/emacs/CheckDoc +checkdoc: + @echo "Checking documentation..." + $(EASK) lint checkdoc --strict + +# Lint package metadata +# +# See https://github.com/purcell/package-lint +lint: + @echo "Linting..." + $(EASK) lint package + +# Generate autoloads file +# +# NOTE: This is generally unnecessary +autoloads: + @echo "Generating autoloads..." + $(EASK) autoloads + +# Generate -pkg file +# +# NOTE: This is generally unnecessary +pkg-file: + @echo "Generating -pkg file..." + $(EASK) pkg-file + +# Clean up +# +# This will clean all the entire workspace including the following folders +# and files +# +# - .eask folder (sandbox) +# - all .elc files +clean: + $(EASK) clean-all diff --git a/README.md b/README.md new file mode 100644 index 0000000..5063d8b --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# npm-transient +> A transient menu for NPM projects diff --git a/README.org b/README.org new file mode 100644 index 0000000..9470e12 --- /dev/null +++ b/README.org @@ -0,0 +1,7 @@ +#+title: npm-transient +#+author: Lucien Cartier-Tilet +#+email: lucien@phundrak.com + +#+begin_quote +A transient menu for NPM  projects +#+end_quote diff --git a/npm-transient.el b/npm-transient.el new file mode 100644 index 0000000..d215c45 --- /dev/null +++ b/npm-transient.el @@ -0,0 +1,236 @@ +;;; npm-transient.el --- A transient menu for NPM projects -*- lexical-binding: t; -*- + +;; Copyright (C) 2022 Lucien Cartier-Tilet + +;; Author: Lucien Cartier-Tilet +;; Maintainer: Lucien Cartier-Tilet +;; URL: https://labs.phundrak.com/phundrak/npm-transient.el +;; Version: 0.1.0 +;; Package-Requires: ((emacs "25.1") (transient "0.3.7")) +;; Keywords: npm transient convenience project javascript typescript node yarn pnpm + +;; This file is not part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: +;; +;; A transient menu for NPM projects +;; + +;;; Code: + +(require 'transient) + + +;;; Internal functions +(defun npm-transient--dummy () + "Dummy function for development purposes only. +Display ARGS." + (interactive) + (message "=== Dummy function.")) + + +;;; Group and Custom Variables +(defgroup npm-transient nil + "Customization group for `npm-transient'." + :group 'applications + :group 'convenience + :group 'tools + :prefix "npm-transient-" + :link '(url-link :tag "Gitea" "https://labs.phundrak.com/phundrak/npm-transient.el")) + +(defconst npm-transient--package-managers '(npm yarn pnpm) + "Package managers supported by `npm-transient'.") + +(defclass npm-transient-package-manager () + ((name :initarg :name + :initform nil + :type symbol + :custom symbol + :documentation "Name of the package manager.") + (install :initarg :install-cmd + :initform "install" + :type string + :custom string + :documentation "command for installing dependencies") + (add :initarg :add-cmd + :initform "" + :type string + :custom string + :documentation "command for adding a regular dependency") + (dev-option :initarg :dev-option + :initform "--save-dev" + :type string + :custom string + :documentation "flag for dev commands, such as npm i --save-dev") + (optional-option :initarg :optional-option + :initform "--save-optional" + :type string + :custom string + :documentation "flag for optional commands, such as npm i --save-optional") + (peer-option :initarg :peer-option + :initform "--save-peer" + :type string + :custom string + :documentation "flag for peer commands, such as npm i --save-peer") + (prod-option :initarg :prod-option + :initform "--save-prod" + :type string + :custom string + :documentation "flag for prod commands, such as npm i --save-prod") + (uninstall :initarg :uninstall-cmd + :initform "" + :type string + :custom string + :documentation "command for removing a dependency") + (list :initarg :list-cmd + :initform "list" + :type string + :custom string + :documentation "command for listing dependencies") + (init :initarg :init-cmd + :initform "init" + :type string + :custom string + :documentation "command for initializing a project") + (run :initarg :run-cmd + :initform "" + :type string + :custom string + :documentation "command for running scripts"))) + +(defconst npm-transient-npm + (npm-transient-package-manager :name 'npm + :add-cmd "install" + :uninstall-cmd "uninstall" + :run-cmd "run") + "Properties for the npm package manager.") + +(defconst npm-transient-yarn + (npm-transient-package-manager :name 'yarn + :add-cmd "add" + :dev-option "--dev" + :optional-option "--optional" + :peer-option "--peer" + :prod-option "--prod" + :uninstall-cmd "remove" + :list-cmd "list" + :init-cmd "init" + :run-cmd "") + "Properties for the yarn package manager.") + +(defconst npm-transient-pnpm + (npm-transient-package-manager :name 'pnpm + :install-cmd "install" + :add-cmd "add" + :add-dev-cmd "add -D" + :uninstall-cmd "remove" + :list-cmd "list" + :init-cmd "init" + :run-cmd "")) + + +;;; Transients +(eval-when-compile + (defmacro npm-transient--def-action (name description transient &rest body) + "Create a function called from TRANSIENT. +DESCRIPTION is the docstring of the function named +npm-transient--action-NAME, and it gets BODY as its body. + +This macro is inspired by Tecosaur’s screenshot.el" + `(defun ,(intern (concat "npm-transient--action-" name)) (&optional _args) + ,(concat description " +This function is meant to be called by a transient.") + (interactive + (list (transient-args ,transient))) + ,@body)) + + (npm-transient--def-action + "delete-node-modules" + "Delete the current project’s \\='node_modules\\=' directory. +This function will search the root of the project and delete its +\\='node_modules\\=' directory, unless it is located in the +user’s home directory." + 'npm-transient-main + nil) + + (npm-transient--def-action + "delete-package-manager-files" + "Delete the current project’s \\='node_modules\\=' and lock file. +This function will search for the root of the project and delete +its \\='node_modules\\=' directory as well as the current package +manager’s lock file, unless the project root is located in the +user’s home directory." + 'npm-transient-main + nil) + + (defmacro npm-transient--def-infix (key name description type version default &rest reader) + "Define infix and its corresponding variable at once. +The variable is named bitwarden-NAME is of type TYPE, has a +DESCRIPTION and a specified VERSION. +The KEY and READER are for the infix declaration. + +This macro is inspired by Tecosaur’s screenshot.el" + (let ((var-name (concat "npm-transient--" name))) + `(progn + (defcustom ,(intern var-name) ,default + ,description + :type ,type + :group 'npm-transient + :version ,version) + (transient-define-infix ,(intern (concat "npm-transient--set-" name)) () + "Set npm-transient options." + :class 'transient-lisp-variable + :variable ',(intern var-name) + :key ,key + :description ,description + :argument ,(concat "--" name) + :reader (lambda (&rest _) ,@reader))))) + + (npm-transient--def-infix + "-p" "package-manager" "Package manager" + 'symbol "0.1.0" + 'npm + (completing-read "Package manager: " + npm-transient--package-managers + nil t))) + + +(transient-define-prefix npm-transient-main () + ["Options" + (npm-transient--set-package-manager)] + ["Dependencies" + ("i" "Install dependencies" npm-transient--dummy) + ("a" "Add dependency" npm-transient--dummy) + ("d" "Add dev dependency" npm-transient--dummy) + ("u" "Uninstall dependency" npm-transient--dummy) + ("l" "List dependencies" npm-transient--dummy)] + ["Action" + ("n" "Initialize" npm-transient--dummy) + ("r" "Run script" npm-transient--dummy) + ("v" "Visit project file" npm-transient--dummy)] + ["Clear" + ("c" "Clean node_modules" npm-transient--action-delete-node-modules) + ("C" "Clear package manager files" npm-transient--action-delete-package-manager-files) + ("q" "Quit" (lambda () (interactive) nil))]) + +;;;###autoload +(defun npm-transient () + "Call the main transient for npm-transient." + (interactive) + (call-interactively #'npm-transient-main)) + +(provide 'npm-transient) +;;; npm-transient.el ends here