@altano/repository-tools 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # repository-tools
2
2
 
3
+ [![npm](https://badgen.net/npm/v/@altano/repository-tools)](https://www.npmjs.com/package/@altano/repository-tools) ![Typed with TypeScript](https://badgen.net/npm/types/@altano/repository-tools) ![ESM only](https://badgen.net/badge/module/esm%20only?icon=js)
4
+
3
5
  Misc tools for dealing with repositories of multiple version control systems
4
6
 
5
7
  ## Supported Version Control Systems
@@ -26,3 +28,14 @@ Example:
26
28
  ```ts
27
29
  await findRoot("/my-git-repo/some/subdirectory"); // => "/my-git-repo"
28
30
  ```
31
+
32
+ ## Importing
33
+
34
+ NOTE: As of v1.0.0 this is an ESM-only module package. It can be imported as an ESM module from any Node.js version but if requiring this package from a CJS package, you must use Node.js v20.19.0+ or v22.12.0+. If you get a `ERR_REQUIRE_ESM` error when calling `require("@altano/repository-tools")` make sure you're on a new enough version of Node.js.
35
+
36
+ You may import all the tools, or import functions directly:
37
+
38
+ | Using sub-path exports | Import to use |
39
+ | ---------------------- | ------------------------------------------------------------------ |
40
+ | No | `import { findRoot } from "@altano/repository-tools";` |
41
+ | Yes | `import { findRoot } from "@altano/repository-tools/findRoot.js";` |
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { exec, execFile } from "child_process";
3
2
  export { execSync, execFileSync } from "child_process";
4
3
  export declare const execAsync: typeof exec.__promisify__;
@@ -1,6 +1,6 @@
1
1
  type RepositoryCommand = "git" | "hg" | "sl" | "svn" | "svnadmin" | "svnrdump";
2
2
  export declare function repositoryExec(cwd: string, command: RepositoryCommand, args: readonly string[]): Promise<string>;
3
3
  export declare function repositoryExecSync(cwd: string, command: RepositoryCommand, args: readonly string[]): string;
4
- export declare const createExecForDirectory: (cwd: string) => (command: RepositoryCommand, args: readonly string[]) => Promise<string>;
4
+ export declare const createExecForDirectory: (cwd: string) => ((command: RepositoryCommand, args: readonly string[]) => Promise<string>);
5
5
  export {};
6
6
  //# sourceMappingURL=repositoryCommand.d.ts.map
@@ -39,7 +39,7 @@ async function repositoryExec(cwd, command, args) {
39
39
  ...environment[command]
40
40
  }
41
41
  }).then(({ stdout, stderr }) => {
42
- return stderr ? Promise.reject(stderr.trim()) : stdout.trim();
42
+ return stderr ? Promise.reject(new Error(stderr.trim())) : stdout.trim();
43
43
  });
44
44
  }
45
45
  function repositoryExecSync(cwd, command, args) {
package/package.json CHANGED
@@ -1,31 +1,7 @@
1
1
  {
2
2
  "name": "@altano/repository-tools",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "Misc tools for dealing with repositories of multiple version control systems (git, svn, etc)",
5
- "main": "./dist/cjs/index.js",
6
- "module": "./dist/esm/index.js",
7
- "exports": {
8
- ".": {
9
- "import": "./dist/esm/index.js",
10
- "require": "./dist/cjs/index.js"
11
- },
12
- "./*": {
13
- "import": "./dist/esm/*.js",
14
- "require": "./dist/cjs/*.js"
15
- }
16
- },
17
- "type": "module",
18
- "sideEffects": false,
19
- "files": [
20
- "dist/**/*.js",
21
- "dist/**/*.d.ts"
22
- ],
23
- "repository": {
24
- "type": "git",
25
- "url": "https://github.com/altano/npm-packages",
26
- "directory": "packages/repository-tools"
27
- },
28
- "homepage": "https://github.com/altano/npm-packages/tree/main/packages/repository-tools",
29
5
  "keywords": [
30
6
  "repository",
31
7
  "root",
@@ -33,50 +9,68 @@
33
9
  "mercurial",
34
10
  "sapling"
35
11
  ],
12
+ "homepage": "https://github.com/altano/npm-packages/tree/main/packages/repository-tools",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/altano/npm-packages",
16
+ "directory": "packages/repository-tools"
17
+ },
18
+ "license": "ISC",
36
19
  "author": {
37
20
  "name": "Alan Norbauer",
38
21
  "email": "altano@gmail.com",
39
22
  "url": "https://alan.norbauer.com"
40
23
  },
41
- "license": "ISC",
24
+ "sideEffects": false,
25
+ "type": "module",
26
+ "exports": {
27
+ ".": "./dist/index.js",
28
+ "./*": "./dist/*"
29
+ },
30
+ "main": "./dist/index.js",
31
+ "module": "./dist/index.js",
32
+ "files": [
33
+ "dist/**/*.js",
34
+ "dist/**/*.d.ts"
35
+ ],
42
36
  "devDependencies": {
43
- "@types/node": "^20.11.25",
44
- "@vitest/coverage-v8": "^1.4.0",
45
- "@vitest/expect": "^1.4.0",
46
- "@vitest/ui": "^1.3.1",
47
- "eslint": "^8.57.0",
37
+ "@arethetypeswrong/cli": "^0.17.4",
38
+ "@types/node": "^22.13.10",
39
+ "@vitest/coverage-v8": "^3.1.1",
40
+ "@vitest/expect": "^3.1.1",
41
+ "depcheck": "^1.4.7",
42
+ "eslint": "^9.23.0",
48
43
  "find-cache-dir": "^5.0.0",
49
44
  "memize": "^2.1.0",
50
- "npm-run-all": "^4.1.5",
51
- "prettier": "^3.2.5",
45
+ "prettier": "^3.5.3",
52
46
  "ts-assert-unreachable": "^0.0.9",
53
- "typescript": "^5.4.2",
54
- "vite": "^5.2.8",
55
- "vitest": "^1.4.0",
47
+ "typescript": "^5.8.2",
48
+ "vite": "^6.2.4",
49
+ "vitest": "^3.1.1",
50
+ "@altano/testing": "0.0.0",
56
51
  "@altano/tsconfig": "0.0.0",
57
- "@altano/vitest-plugins": "0.1.1",
58
- "eslint-config-altano": "0.0.0"
52
+ "@altano/build-config": "0.0.0"
59
53
  },
60
54
  "publishConfig": {
61
55
  "access": "public"
62
56
  },
63
57
  "scripts": {
64
- "build": "tsup --config build-config/tsup.config.node-hybrid.ts",
65
- "build:types:cjs": "tsc --project tsconfig.declarations-cjs.json",
66
- "build:types:esm": "tsc --project tsconfig.declarations-esm.json",
58
+ "build": "tsup --config build-config/tsup.config.node.ts",
59
+ "build:types": "tsc --project tsconfig.declarations.json",
60
+ "check:exports": "attw --pack . --profile esm-only",
61
+ "check:types:src": "tsc --noEmit",
62
+ "check:types:test": "tsc --noEmit --project ./tests/tsconfig.json",
63
+ "check:unused-dependencies": "depcheck",
67
64
  "clean": "rm -rf .turbo && rm -rf .tsbuildinfo && rm -rf node_modules && rm -rf dist",
68
65
  "dev": "pnpm run build --watch",
69
66
  "format": "prettier --check src",
70
67
  "format:fix": "prettier --write src",
71
- "lint": "eslint package.json src/**/*.ts*",
68
+ "lint": "eslint",
72
69
  "lint:fix": "TIMING=1 pnpm lint --fix",
73
70
  "lint:timing": "TIMING=1 pnpm lint",
74
71
  "test:build": "./tests/scripts/createRepositoryBundles.ts",
75
- "test:unit": "run-s test:unit:run",
72
+ "test:unit": "vitest --run",
76
73
  "test:unit:benchmark": "vitest --run bench",
77
- "test:unit:run": "vitest --run",
78
- "test:unit:watch": "vitest",
79
- "typecheck:src": "tsc --noEmit",
80
- "typecheck:test": "tsc --noEmit --project ./tests/tsconfig.json"
74
+ "test:unit:watch": "vitest"
81
75
  }
82
76
  }
package/dist/cjs/exec.js DELETED
@@ -1,38 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var exec_exports = {};
20
- __export(exec_exports, {
21
- execAsync: () => execAsync,
22
- execFileAsync: () => execFileAsync,
23
- execFileSync: () => import_child_process2.execFileSync,
24
- execSync: () => import_child_process2.execSync
25
- });
26
- module.exports = __toCommonJS(exec_exports);
27
- var import_child_process = require("child_process");
28
- var import_node_util = require("node:util");
29
- var import_child_process2 = require("child_process");
30
- const execAsync = (0, import_node_util.promisify)(import_child_process.exec);
31
- const execFileAsync = (0, import_node_util.promisify)(import_child_process.execFile);
32
- // Annotate the CommonJS export names for ESM import in node:
33
- 0 && (module.exports = {
34
- execAsync,
35
- execFileAsync,
36
- execFileSync,
37
- execSync
38
- });
@@ -1,69 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var findRoot_exports = {};
20
- __export(findRoot_exports, {
21
- findRoot: () => findRoot
22
- });
23
- module.exports = __toCommonJS(findRoot_exports);
24
- var import_repositoryCommand = require("./repositoryCommand.js");
25
- async function findGitRoot(directory) {
26
- return (0, import_repositoryCommand.repositoryExec)(directory, "git", [
27
- "rev-parse",
28
- "--quiet",
29
- "--show-toplevel"
30
- ]);
31
- }
32
- async function findSaplingRoot(directory) {
33
- return (0, import_repositoryCommand.repositoryExec)(directory, "sl", ["--quiet", "root"]);
34
- }
35
- async function findMercurialRoot(directory) {
36
- return (0, import_repositoryCommand.repositoryExec)(directory, "hg", ["--quiet", "root"]);
37
- }
38
- async function findSubversionRoot(directory) {
39
- return (0, import_repositoryCommand.repositoryExec)(directory, "svn", ["info", "--show-item", "wc-root"]);
40
- }
41
- const findMethods = [
42
- findGitRoot,
43
- // most used and fastest check
44
- findSubversionRoot,
45
- // next highest market share
46
- findSaplingRoot,
47
- // much smaller market share, but much faster
48
- findMercurialRoot
49
- // slow af
50
- ];
51
- async function findRoot(directory) {
52
- for (const method of findMethods) {
53
- try {
54
- const result = await method(directory);
55
- if (result != null && result !== "") {
56
- return result;
57
- }
58
- } catch (e) {
59
- if (e instanceof Error && "code" in e && e.code === "ENOTDIR") {
60
- throw new Error(`Given path isn't a directory: ${directory}`);
61
- }
62
- }
63
- }
64
- return null;
65
- }
66
- // Annotate the CommonJS export names for ESM import in node:
67
- 0 && (module.exports = {
68
- findRoot
69
- });
@@ -1,69 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var findRootSync_exports = {};
20
- __export(findRootSync_exports, {
21
- findRootSync: () => findRootSync
22
- });
23
- module.exports = __toCommonJS(findRootSync_exports);
24
- var import_repositoryCommand = require("./repositoryCommand.js");
25
- function findGitRoot(cwd) {
26
- return (0, import_repositoryCommand.repositoryExecSync)(cwd, "git", [
27
- "rev-parse",
28
- "--quiet",
29
- "--show-toplevel"
30
- ]);
31
- }
32
- function findSaplingRoot(cwd) {
33
- return (0, import_repositoryCommand.repositoryExecSync)(cwd, "sl", ["--quiet", "root"]);
34
- }
35
- function findMercurialRoot(cwd) {
36
- return (0, import_repositoryCommand.repositoryExecSync)(cwd, "hg", ["--quiet", "root"]);
37
- }
38
- function findSubversionRoot(cwd) {
39
- return (0, import_repositoryCommand.repositoryExecSync)(cwd, "svn", ["info", "--show-item", "wc-root"]);
40
- }
41
- const findMethods = [
42
- findGitRoot,
43
- // most used and fastest check
44
- findSubversionRoot,
45
- // next highest market share
46
- findSaplingRoot,
47
- // much smaller market share, but much faster
48
- findMercurialRoot
49
- // slow af
50
- ];
51
- function findRootSync(directory) {
52
- for (const method of findMethods) {
53
- try {
54
- const result = method(directory);
55
- if (result != null && result !== "") {
56
- return result;
57
- }
58
- } catch (e) {
59
- if (e instanceof Error && "code" in e && e.code === "ENOTDIR") {
60
- throw new Error(`Given path isn't a directory: ${directory}`);
61
- }
62
- }
63
- }
64
- return null;
65
- }
66
- // Annotate the CommonJS export names for ESM import in node:
67
- 0 && (module.exports = {
68
- findRootSync
69
- });
package/dist/cjs/index.js DELETED
@@ -1,24 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __copyProps = (to, from, except, desc) => {
7
- if (from && typeof from === "object" || typeof from === "function") {
8
- for (let key of __getOwnPropNames(from))
9
- if (!__hasOwnProp.call(to, key) && key !== except)
10
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
- }
12
- return to;
13
- };
14
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
- var src_exports = {};
17
- module.exports = __toCommonJS(src_exports);
18
- __reExport(src_exports, require("./findRoot.js"), module.exports);
19
- __reExport(src_exports, require("./findRootSync.js"), module.exports);
20
- // Annotate the CommonJS export names for ESM import in node:
21
- 0 && (module.exports = {
22
- ...require("./findRoot.js"),
23
- ...require("./findRootSync.js")
24
- });
@@ -1,87 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var repositoryCommand_exports = {};
20
- __export(repositoryCommand_exports, {
21
- createExecForDirectory: () => createExecForDirectory,
22
- repositoryExec: () => repositoryExec,
23
- repositoryExecSync: () => repositoryExecSync
24
- });
25
- module.exports = __toCommonJS(repositoryCommand_exports);
26
- var import_exec = require("./exec.js");
27
- const environment = {
28
- git: {
29
- // non-interactive
30
- GIT_TERMINAL_PROMPT: "0",
31
- // don't use global config
32
- GIT_CONFIG_GLOBAL: "/dev/null",
33
- GIT_CONFIG_SYSTEM: "/dev/null",
34
- // user config
35
- GIT_COMMITTER_NAME: "alan",
36
- GIT_COMMITTER_EMAIL: "alan@example.com",
37
- GIT_AUTHOR_NAME: "alan",
38
- GIT_AUTHOR_EMAIL: "alan@example.com"
39
- },
40
- hg: {
41
- // don't use global config
42
- HGRCPATH: "/dev/null",
43
- // don't use global config
44
- HGUSER: "alan",
45
- EMAIL: "alan@example.com"
46
- },
47
- sl: {
48
- // don't use global config
49
- HGRCPATH: "/dev/null",
50
- // don't use global config
51
- HGUSER: "alan",
52
- EMAIL: "alan@example.com"
53
- },
54
- svn: {},
55
- svnadmin: {},
56
- svnrdump: {}
57
- };
58
- async function repositoryExec(cwd, command, args) {
59
- return (0, import_exec.execFileAsync)(command, args, {
60
- cwd,
61
- encoding: "utf8",
62
- env: {
63
- ...process.env,
64
- ...environment[command]
65
- }
66
- }).then(({ stdout, stderr }) => {
67
- return stderr ? Promise.reject(stderr.trim()) : stdout.trim();
68
- });
69
- }
70
- function repositoryExecSync(cwd, command, args) {
71
- const result = (0, import_exec.execFileSync)(command, args, {
72
- cwd,
73
- encoding: "utf8",
74
- env: {
75
- ...process.env,
76
- ...environment[command]
77
- }
78
- }).trim();
79
- return result;
80
- }
81
- const createExecForDirectory = (cwd) => repositoryExec.bind(null, cwd);
82
- // Annotate the CommonJS export names for ESM import in node:
83
- 0 && (module.exports = {
84
- createExecForDirectory,
85
- repositoryExec,
86
- repositoryExecSync
87
- });
package/dist/cjs/types.js DELETED
@@ -1,33 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var types_exports = {};
20
- __export(types_exports, {
21
- repositoryTypes: () => repositoryTypes
22
- });
23
- module.exports = __toCommonJS(types_exports);
24
- const repositoryTypes = [
25
- "git",
26
- "mercurial",
27
- "sapling",
28
- "subversion"
29
- ];
30
- // Annotate the CommonJS export names for ESM import in node:
31
- 0 && (module.exports = {
32
- repositoryTypes
33
- });
@@ -1,6 +0,0 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- import { exec, execFile } from "child_process";
3
- export { execSync, execFileSync } from "child_process";
4
- export declare const execAsync: typeof exec.__promisify__;
5
- export declare const execFileAsync: typeof execFile.__promisify__;
6
- //# sourceMappingURL=exec.d.ts.map
@@ -1,11 +0,0 @@
1
- /**
2
- * Find the root path of the repository containing the given directory.
3
- *
4
- * @returns null if not found or the path of the repository root as a string
5
- */
6
- export declare function findRoot(
7
- /**
8
- * The directory path of anything in a version-controlled repository
9
- */
10
- directory: string): Promise<string | null>;
11
- //# sourceMappingURL=findRoot.d.ts.map
@@ -1,11 +0,0 @@
1
- /**
2
- * Find the root path of the repository containing the given directory.
3
- *
4
- * @returns null if not found or the path of the repository root as a string
5
- */
6
- export declare function findRootSync(
7
- /**
8
- * The directory path of anything in a version-controlled repository
9
- */
10
- directory: string): string | null;
11
- //# sourceMappingURL=findRootSync.d.ts.map
@@ -1,3 +0,0 @@
1
- export * from "./findRoot.js";
2
- export * from "./findRootSync.js";
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,6 +0,0 @@
1
- type RepositoryCommand = "git" | "hg" | "sl" | "svn" | "svnadmin" | "svnrdump";
2
- export declare function repositoryExec(cwd: string, command: RepositoryCommand, args: readonly string[]): Promise<string>;
3
- export declare function repositoryExecSync(cwd: string, command: RepositoryCommand, args: readonly string[]): string;
4
- export declare const createExecForDirectory: (cwd: string) => (command: RepositoryCommand, args: readonly string[]) => Promise<string>;
5
- export {};
6
- //# sourceMappingURL=repositoryCommand.d.ts.map
@@ -1,3 +0,0 @@
1
- export declare const repositoryTypes: readonly ["git", "mercurial", "sapling", "subversion"];
2
- export type RepositoryType = (typeof repositoryTypes)[number];
3
- //# sourceMappingURL=types.d.ts.map
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes