From 859a2b4df45ee1ad6a0dc8f257c2db224044c48b Mon Sep 17 00:00:00 2001 From: Nikolay Gagarinov Date: Tue, 2 Jun 2026 15:51:23 +0500 Subject: [PATCH] =?UTF-8?q?add(40-define-functions):=20=D1=83=D1=80=D0=BE?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=BF=D1=80=D0=BE=20=D0=BC=D0=BE=D0=B4=D1=83?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=B8=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D1=8B=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=B0=D0=BD=D0=B0=D0=BB=D0=BE=D0=B3=D0=B8=D0=B8?= =?UTF-8?q?=20=D1=81=20Python?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавляет два урока в конец модуля 40-define-functions, повторяя структуру exercises-python (350-modules, 400-packages): - 460-modules: import/export, именованный импорт, export default, переименование через as, стандартные модули - 470-packages: npm-пакеты, импорт по имени, subpath-модули одного пакета, package.json/exports, node_modules Упражнения используют существующий внутренний пакет hexlet-basics (string/math) — без изменений в src/hexlet и package.json. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../40-define-functions/460-modules/Makefile | 2 + .../460-modules/description.es.yml | 38 +++++++++ .../460-modules/en/EXERCISE.md | 13 +++ .../460-modules/en/README.md | 83 +++++++++++++++++++ .../460-modules/en/data.yml | 5 ++ .../460-modules/es/EXERCISE.md | 13 +++ .../460-modules/es/README.md | 83 +++++++++++++++++++ .../460-modules/es/data.yml | 5 ++ .../40-define-functions/460-modules/index.js | 7 ++ .../460-modules/ru/EXERCISE.md | 13 +++ .../460-modules/ru/README.md | 83 +++++++++++++++++++ .../460-modules/ru/data.yml | 5 ++ .../40-define-functions/460-modules/test.js | 9 ++ .../40-define-functions/470-packages/Makefile | 2 + .../470-packages/description.es.yml | 36 ++++++++ .../470-packages/en/EXERCISE.md | 14 ++++ .../470-packages/en/README.md | 51 ++++++++++++ .../470-packages/en/data.yml | 5 ++ .../470-packages/es/EXERCISE.md | 14 ++++ .../470-packages/es/README.md | 51 ++++++++++++ .../470-packages/es/data.yml | 5 ++ .../40-define-functions/470-packages/index.js | 7 ++ .../470-packages/ru/EXERCISE.md | 14 ++++ .../470-packages/ru/README.md | 51 ++++++++++++ .../470-packages/ru/data.yml | 5 ++ .../40-define-functions/470-packages/test.js | 10 +++ 26 files changed, 624 insertions(+) create mode 100644 modules/40-define-functions/460-modules/Makefile create mode 100644 modules/40-define-functions/460-modules/description.es.yml create mode 100644 modules/40-define-functions/460-modules/en/EXERCISE.md create mode 100644 modules/40-define-functions/460-modules/en/README.md create mode 100644 modules/40-define-functions/460-modules/en/data.yml create mode 100644 modules/40-define-functions/460-modules/es/EXERCISE.md create mode 100644 modules/40-define-functions/460-modules/es/README.md create mode 100644 modules/40-define-functions/460-modules/es/data.yml create mode 100644 modules/40-define-functions/460-modules/index.js create mode 100644 modules/40-define-functions/460-modules/ru/EXERCISE.md create mode 100644 modules/40-define-functions/460-modules/ru/README.md create mode 100644 modules/40-define-functions/460-modules/ru/data.yml create mode 100644 modules/40-define-functions/460-modules/test.js create mode 100644 modules/40-define-functions/470-packages/Makefile create mode 100644 modules/40-define-functions/470-packages/description.es.yml create mode 100644 modules/40-define-functions/470-packages/en/EXERCISE.md create mode 100644 modules/40-define-functions/470-packages/en/README.md create mode 100644 modules/40-define-functions/470-packages/en/data.yml create mode 100644 modules/40-define-functions/470-packages/es/EXERCISE.md create mode 100644 modules/40-define-functions/470-packages/es/README.md create mode 100644 modules/40-define-functions/470-packages/es/data.yml create mode 100644 modules/40-define-functions/470-packages/index.js create mode 100644 modules/40-define-functions/470-packages/ru/EXERCISE.md create mode 100644 modules/40-define-functions/470-packages/ru/README.md create mode 100644 modules/40-define-functions/470-packages/ru/data.yml create mode 100644 modules/40-define-functions/470-packages/test.js diff --git a/modules/40-define-functions/460-modules/Makefile b/modules/40-define-functions/460-modules/Makefile new file mode 100644 index 00000000..d0d0a48c --- /dev/null +++ b/modules/40-define-functions/460-modules/Makefile @@ -0,0 +1,2 @@ +test: + @ test.sh diff --git a/modules/40-define-functions/460-modules/description.es.yml b/modules/40-define-functions/460-modules/description.es.yml new file mode 100644 index 00000000..1c02d2e6 --- /dev/null +++ b/modules/40-define-functions/460-modules/description.es.yml @@ -0,0 +1,38 @@ +--- + +name: Módulos +theory: | + + Mientras un programa es pequeño, todo el código cabe en un solo archivo. Pero con el tiempo el programa crece, y orientarse en un único archivo se vuelve difícil. Para dividir el código en partes lógicas, en JavaScript se usan los módulos: un archivo de código independiente es un módulo. + + Un módulo decide qué entregar al exterior con la palabra clave `export`, y otro archivo lo conecta mediante `import`: + + ```javascript + import { length } from 'hexlet-basics/string'; + + console.log(length('Hello!')); // => 6 + ``` + + De un mismo módulo se pueden importar varios nombres a la vez: + + ```javascript + import { reverse, toUpperCase } from 'hexlet-basics/string'; + + console.log(reverse('hexlet')); // => telxeh + console.log(toUpperCase('hexlet')); // => HEXLET + ``` + +instructions: | + + Implementa la función `mirror()`. Recibe una cadena, la invierte y la convierte a mayúsculas, y devuelve el resultado. + + Usa las funciones `reverse()` y `toUpperCase()` del módulo `hexlet-basics/string`. Escribe la importación tú mismo. + + ```javascript + mirror('hello'); // => 'OLLEH' + mirror('Hexlet'); // => 'TELXEH' + ``` + +tips: + - | + [Documentación sobre módulos (import/export)](https://developer.mozilla.org/es/docs/Web/JavaScript/Guide/Modules) diff --git a/modules/40-define-functions/460-modules/en/EXERCISE.md b/modules/40-define-functions/460-modules/en/EXERCISE.md new file mode 100644 index 00000000..949c3129 --- /dev/null +++ b/modules/40-define-functions/460-modules/en/EXERCISE.md @@ -0,0 +1,13 @@ +Implement the `mirror()` function. It takes a string, reverses it, and converts it to upper case, then returns the result. + +Use the `reverse()` and `toUpperCase()` functions from the `hexlet-basics/string` module. You need to write the import yourself. + +```javascript +mirror('hello'); // => 'OLLEH' +mirror('Hexlet'); // => 'TELXEH' +``` + +## Hint + +* At the beginning of the file, import the functions you need: `import { reverse, toUpperCase } from 'hexlet-basics/string';` +* First reverse the string, then convert the result to upper case diff --git a/modules/40-define-functions/460-modules/en/README.md b/modules/40-define-functions/460-modules/en/README.md new file mode 100644 index 00000000..9d433f97 --- /dev/null +++ b/modules/40-define-functions/460-modules/en/README.md @@ -0,0 +1,83 @@ +As long as a program is small, all the code can live in a single file. This approach is convenient for simple examples and small tasks. But over time a program starts to grow. When there is a lot of code, it becomes hard to navigate a single file. Real applications consist of tens of thousands of lines (at least) and hundreds of files. + +To split a program into separate logical parts, JavaScript uses modules. A separate file with code is a module. The language provides mechanisms that let one file use functions and constants from another. + +## export and import + +A module decides what to expose. The `export` keyword is used for this. Another file pulls in what was exported via `import`. + +You have probably already seen lines like this at the beginning of some exercises — now let's figure out what they mean: + +```javascript +import { length } from 'hexlet-basics/string'; + +console.log(length('Hello!')); // => 6 +``` + +This line connects the `length` function from the `hexlet-basics/string` module and makes it available in the current file. + +## Named imports + +You can import several names from one module at once by listing them in curly braces: + +```javascript +import { reverse, toUpperCase } from 'hexlet-basics/string'; + +console.log(reverse('hexlet')); // => telxeh +console.log(toUpperCase('hexlet')); // => HEXLET +``` + +After such an import, you call the functions directly, by their names. This is convenient: you don't have to specify which module a function came from every time. + +## Default export + +To export something, a module marks it with the word `export`. There are two kinds of export. A named one — there can be as many exported names as you like: + +```javascript +// string.js +const reverse = (s) => s.split('').reverse().join(''); +const length = (s) => s.length; + +export { reverse, length }; +``` + +And a default export — a module can have only one of those. You have already come across it when defining functions: + +```javascript +// sum.js +const sum = (a, b) => a + b; + +export default sum; +``` + +A default import is written without curly braces, and you may pick any name for it: + +```javascript +import sum from './sum.js'; + +console.log(sum(2, 3)); // => 5 +``` + +## Renaming on import + +Sometimes a name from a module is already taken in the current file. To avoid a conflict, an import can be renamed with `as`: + +```javascript +import { reverse as reverseString } from 'hexlet-basics/string'; + +console.log(reverseString('hexlet')); // => telxeh +``` + +Now the function is available under the name `reverseString`, while the original name `reverse` stays free. + +## Standard modules + +Every language ships with a set of ready-made functions. In JavaScript, most of them are available globally and need no import — for example, the `Math` object for math or `console` for output. + +But JavaScript runs in different environments. The Node.js server environment has built-in modules that need to be imported. They are imported with the `node:` prefix — for example, the `node:fs` module for working with files: + +```javascript +import { readFile } from 'node:fs/promises'; +``` + +Ready-made functions can be taken not only from standard modules but also from third-party ones. We'll talk about how those are distributed in the next lesson. diff --git a/modules/40-define-functions/460-modules/en/data.yml b/modules/40-define-functions/460-modules/en/data.yml new file mode 100644 index 00000000..bdab6e10 --- /dev/null +++ b/modules/40-define-functions/460-modules/en/data.yml @@ -0,0 +1,5 @@ +--- +name: Modules +tips: + - | + [Documentation on modules (import/export)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) diff --git a/modules/40-define-functions/460-modules/es/EXERCISE.md b/modules/40-define-functions/460-modules/es/EXERCISE.md new file mode 100644 index 00000000..d6ed95b2 --- /dev/null +++ b/modules/40-define-functions/460-modules/es/EXERCISE.md @@ -0,0 +1,13 @@ +Implementa la función `mirror()`. Recibe una cadena, la invierte y la convierte a mayúsculas, y luego devuelve el resultado. + +Usa las funciones `reverse()` y `toUpperCase()` del módulo `hexlet-basics/string`. Debes escribir la importación tú mismo. + +```javascript +mirror('hello'); // => 'OLLEH' +mirror('Hexlet'); // => 'TELXEH' +``` + +## Pista + +* Al comienzo del archivo, importa las funciones que necesitas: `import { reverse, toUpperCase } from 'hexlet-basics/string';` +* Primero invierte la cadena y luego convierte el resultado a mayúsculas diff --git a/modules/40-define-functions/460-modules/es/README.md b/modules/40-define-functions/460-modules/es/README.md new file mode 100644 index 00000000..0a743b1e --- /dev/null +++ b/modules/40-define-functions/460-modules/es/README.md @@ -0,0 +1,83 @@ +Mientras un programa es pequeño, todo el código puede vivir en un solo archivo. Este enfoque es cómodo para ejemplos sencillos y tareas pequeñas. Pero con el tiempo el programa empieza a crecer. Cuando hay mucho código, resulta difícil orientarse en un único archivo. Las aplicaciones reales constan de decenas de miles de líneas (como mínimo) y cientos de archivos. + +Para dividir un programa en partes lógicas separadas, en JavaScript se usan los módulos. Un archivo de código independiente es un módulo. El lenguaje proporciona mecanismos con los que un archivo puede usar funciones y constantes de otro. + +## export e import + +El módulo decide qué entregar al exterior. Para ello se usa la palabra clave `export`. Otro archivo conecta lo exportado mediante `import`. + +Probablemente ya hayas visto líneas como esta al comienzo de algunos ejercicios — ahora veamos qué significan: + +```javascript +import { length } from 'hexlet-basics/string'; + +console.log(length('Hello!')); // => 6 +``` + +Esta línea conecta la función `length` del módulo `hexlet-basics/string` y la hace disponible en el archivo actual. + +## Importación con nombre + +De un mismo módulo se pueden importar varios nombres a la vez, enumerándolos entre llaves: + +```javascript +import { reverse, toUpperCase } from 'hexlet-basics/string'; + +console.log(reverse('hexlet')); // => telxeh +console.log(toUpperCase('hexlet')); // => HEXLET +``` + +Tras esta importación, las funciones se llaman directamente, por sus nombres. Esto es cómodo: no hace falta indicar cada vez de qué módulo proviene una función. + +## Exportación por defecto + +Para exportar algo, el módulo lo marca con la palabra `export`. Hay dos tipos de exportación. La nombrada: puede haber tantos nombres exportados como se quiera: + +```javascript +// string.js +const reverse = (s) => s.split('').reverse().join(''); +const length = (s) => s.length; + +export { reverse, length }; +``` + +Y la exportación por defecto: un módulo solo puede tener una. Ya te has topado con ella al definir funciones: + +```javascript +// sum.js +const sum = (a, b) => a + b; + +export default sum; +``` + +La importación por defecto se escribe sin llaves, y se le puede dar cualquier nombre: + +```javascript +import sum from './sum.js'; + +console.log(sum(2, 3)); // => 5 +``` + +## Renombrar al importar + +A veces un nombre de un módulo ya está ocupado en el archivo actual. Para evitar el conflicto, la importación se puede renombrar con `as`: + +```javascript +import { reverse as reverseString } from 'hexlet-basics/string'; + +console.log(reverseString('hexlet')); // => telxeh +``` + +Ahora la función está disponible bajo el nombre `reverseString`, mientras que el nombre original `reverse` queda libre. + +## Módulos estándar + +Cada lenguaje viene con un conjunto de funciones listas para usar. En JavaScript, la mayoría de ellas están disponibles de forma global y no requieren importación — por ejemplo, el objeto `Math` para las matemáticas o `console` para la salida. + +Pero JavaScript se ejecuta en distintos entornos. El entorno de servidor Node.js tiene módulos integrados que hay que importar. Se importan con el prefijo `node:` — por ejemplo, el módulo `node:fs` para trabajar con archivos: + +```javascript +import { readFile } from 'node:fs/promises'; +``` + +Las funciones listas se pueden tomar no solo de los módulos estándar, sino también de módulos de terceros. Hablaremos de cómo se distribuyen estos en la siguiente lección. diff --git a/modules/40-define-functions/460-modules/es/data.yml b/modules/40-define-functions/460-modules/es/data.yml new file mode 100644 index 00000000..6270f16a --- /dev/null +++ b/modules/40-define-functions/460-modules/es/data.yml @@ -0,0 +1,5 @@ +--- +name: Módulos +tips: + - | + [Documentación sobre módulos (import/export)](https://developer.mozilla.org/es/docs/Web/JavaScript/Guide/Modules) diff --git a/modules/40-define-functions/460-modules/index.js b/modules/40-define-functions/460-modules/index.js new file mode 100644 index 00000000..a41b13e1 --- /dev/null +++ b/modules/40-define-functions/460-modules/index.js @@ -0,0 +1,7 @@ +// BEGIN +import { reverse, toUpperCase } from 'hexlet-basics/string'; + +const mirror = (text) => toUpperCase(reverse(text)); +// END + +export default mirror; diff --git a/modules/40-define-functions/460-modules/ru/EXERCISE.md b/modules/40-define-functions/460-modules/ru/EXERCISE.md new file mode 100644 index 00000000..5862670a --- /dev/null +++ b/modules/40-define-functions/460-modules/ru/EXERCISE.md @@ -0,0 +1,13 @@ +Реализуйте функцию `mirror()`. Она принимает строку, переворачивает её и переводит в верхний регистр, после чего возвращает результат. + +Используйте функции `reverse()` и `toUpperCase()` из модуля `hexlet-basics/string`. Импорт нужно написать самостоятельно. + +```javascript +mirror('hello'); // => 'OLLEH' +mirror('Hexlet'); // => 'TELXEH' +``` + +## Подсказка + +* В начале файла импортируйте нужные функции: `import { reverse, toUpperCase } from 'hexlet-basics/string';` +* Сначала переверните строку, затем переведите результат в верхний регистр diff --git a/modules/40-define-functions/460-modules/ru/README.md b/modules/40-define-functions/460-modules/ru/README.md new file mode 100644 index 00000000..3e76a5ce --- /dev/null +++ b/modules/40-define-functions/460-modules/ru/README.md @@ -0,0 +1,83 @@ +Пока программа маленькая, весь код можно хранить в одном файле. Такой подход удобен для простых примеров и небольших задач. Но со временем программа начинает расти. Когда кода становится много, ориентироваться в одном файле становится сложно. Реальные приложения состоят из десятков тысяч строк (как минимум) и сотен файлов. + +Чтобы разделить программу на отдельные логические части, в JavaScript используют модули. Отдельный файл с кодом и есть модуль. А язык предоставляет механизмы, с помощью которых один файл может использовать функции и константы из другого. + +## export и import + +Модуль сам решает, что отдать наружу. Для этого используют ключевое слово `export`. Другой файл подключает экспортированное через `import`. + +Скорее всего, такие строки вы уже видели в начале некоторых заданий — теперь разберёмся, что они значат: + +```javascript +import { length } from 'hexlet-basics/string'; + +console.log(length('Hello!')); // => 6 +``` + +Эта строчка подключает функцию `length` из модуля `hexlet-basics/string` и делает её доступной в текущем файле. + +## Именованный импорт + +Из одного модуля можно импортировать сразу несколько имён, перечислив их в фигурных скобках: + +```javascript +import { reverse, toUpperCase } from 'hexlet-basics/string'; + +console.log(reverse('hexlet')); // => telxeh +console.log(toUpperCase('hexlet')); // => HEXLET +``` + +После такого импорта к функциям обращаются напрямую, по их именам. Это удобно: не нужно каждый раз писать, из какого модуля взята функция. + +## Экспорт по умолчанию + +Чтобы что-то экспортировать, модуль помечает это словом `export`. Экспорт бывает двух видов. Именованный — экспортируемых имён может быть сколько угодно: + +```javascript +// string.js +const reverse = (s) => s.split('').reverse().join(''); +const length = (s) => s.length; + +export { reverse, length }; +``` + +И экспорт по умолчанию — он в модуле может быть только один. С таким экспортом вы уже сталкивались, когда определяли функции: + +```javascript +// sum.js +const sum = (a, b) => a + b; + +export default sum; +``` + +Импорт по умолчанию пишется без фигурных скобок, и имя при импорте можно выбрать любое: + +```javascript +import sum from './sum.js'; + +console.log(sum(2, 3)); // => 5 +``` + +## Переименование при импорте + +Иногда имя из модуля уже занято в текущем файле. Чтобы избежать конфликта, импорт можно переименовать через `as`: + +```javascript +import { reverse as reverseString } from 'hexlet-basics/string'; + +console.log(reverseString('hexlet')); // => telxeh +``` + +Теперь функция доступна под именем `reverseString`, а исходное имя `reverse` остаётся свободным. + +## Стандартные модули + +У каждого языка есть набор готовых функций. В JavaScript бо́льшая часть из них доступна глобально и импорта не требует — например, объект `Math` для математики или `console` для вывода. + +Но JavaScript исполняется в разных средах. В серверном окружении Node.js есть встроенные модули, которые нужно подключать. Их подключают с префиксом `node:` — например, модуль `node:fs` для работы с файлами: + +```javascript +import { readFile } from 'node:fs/promises'; +``` + +Готовые функции можно брать не только из стандартных, но и из сторонних модулей. О том, как они распространяются, поговорим в следующем уроке. diff --git a/modules/40-define-functions/460-modules/ru/data.yml b/modules/40-define-functions/460-modules/ru/data.yml new file mode 100644 index 00000000..f7783e54 --- /dev/null +++ b/modules/40-define-functions/460-modules/ru/data.yml @@ -0,0 +1,5 @@ +--- +name: Модули +tips: + - | + [Документация по модулям (import/export)](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Modules) diff --git a/modules/40-define-functions/460-modules/test.js b/modules/40-define-functions/460-modules/test.js new file mode 100644 index 00000000..7d7b87dd --- /dev/null +++ b/modules/40-define-functions/460-modules/test.js @@ -0,0 +1,9 @@ +// @ts-check + +import { expect, test } from 'vitest'; +import mirror from './index.js'; + +test('mirror', () => { + expect(mirror('hello')).toBe('OLLEH'); + expect(mirror('Hexlet')).toBe('TELXEH'); +}); diff --git a/modules/40-define-functions/470-packages/Makefile b/modules/40-define-functions/470-packages/Makefile new file mode 100644 index 00000000..d0d0a48c --- /dev/null +++ b/modules/40-define-functions/470-packages/Makefile @@ -0,0 +1,2 @@ +test: + @ test.sh diff --git a/modules/40-define-functions/470-packages/description.es.yml b/modules/40-define-functions/470-packages/description.es.yml new file mode 100644 index 00000000..83a93bf8 --- /dev/null +++ b/modules/40-define-functions/470-packages/description.es.yml @@ -0,0 +1,36 @@ +--- + +name: Paquetes +theory: | + + A medida que un programa crece, aumenta no solo la cantidad de código, sino también la de módulos, y el código útil se quiere reutilizar en distintos proyectos. En el ecosistema de JavaScript, la unidad de reutilización y distribución es un **paquete** (un paquete de npm): un conjunto de módulos que se publica y se instala como un todo. + + Un paquete se describe con `package.json` y se instala con `npm install` en `node_modules`. Su contenido se importa por el nombre del paquete: + + ```javascript + import { round } from 'hexlet-basics/math'; + + console.log(round(3.14159, 2)); // => 3.14 + ``` + + Un paquete suele contener varios módulos. Para elegir uno, se añade una ruta tras su nombre con `/`: + + ```javascript + import { reverse } from 'hexlet-basics/string'; + import { round } from 'hexlet-basics/math'; + ``` + +instructions: | + + Implementa la función `formatPrice()`. Recibe un número y devuelve su representación como cadena, redondeada a dos decimales. + + Usa la función `round()` del módulo `hexlet-basics/math`. Escribe la importación tú mismo. + + ```javascript + formatPrice(12.3456); // => '12.35' + formatPrice(10); // => '10.00' + ``` + +tips: + - | + [Sobre paquetes y módulos en npm](https://docs.npmjs.com/about-packages-and-modules) diff --git a/modules/40-define-functions/470-packages/en/EXERCISE.md b/modules/40-define-functions/470-packages/en/EXERCISE.md new file mode 100644 index 00000000..6054963a --- /dev/null +++ b/modules/40-define-functions/470-packages/en/EXERCISE.md @@ -0,0 +1,14 @@ +Implement the `formatPrice()` function. It takes a number and returns its string representation rounded to two decimal places. + +Use the `round()` function from the `hexlet-basics/math` module — this is another module of the same `hexlet-basics` package you worked with in the previous lesson. You need to write the import yourself. + +```javascript +formatPrice(12.3456); // => '12.35' +formatPrice(2.5); // => '2.50' +formatPrice(10); // => '10.00' +``` + +## Hint + +* At the beginning of the file, import the function: `import { round } from 'hexlet-basics/math';` +* The second argument of `round()` is the number of decimal places diff --git a/modules/40-define-functions/470-packages/en/README.md b/modules/40-define-functions/470-packages/en/README.md new file mode 100644 index 00000000..af4a3df4 --- /dev/null +++ b/modules/40-define-functions/470-packages/en/README.md @@ -0,0 +1,51 @@ +As a program grows, it is not only the number of lines of code that increases, but also the number of modules. In small projects you can keep dozens of files side by side, but real applications can have hundreds and thousands of files. On top of that, useful code is something you want to reuse across different projects. + +In Python, packages-as-directories are used to group modules. In the JavaScript ecosystem, the unit of reuse and distribution is a **package** (an npm package). A package is a set of modules that is published and installed as a whole. + +## What a package is + +A package is described by a `package.json` file and installed with the `npm install` command into the `node_modules` directory. That is where its modules are imported from. One such package is `hexlet-basics`, the one we import functions from in this course. + +## Importing by package name + +When a package is installed, its contents are imported by the package name rather than by a file path: + +```javascript +import { round } from 'hexlet-basics/math'; + +console.log(round(3.14159, 2)); // => 3.14 +``` + +## One package, several modules + +A package usually contains more than one module. To pick a specific module inside a package, you add a path after its name with `/`: + +```javascript +import { reverse } from 'hexlet-basics/string'; // the string module of the hexlet-basics package +import { round } from 'hexlet-basics/math'; // the math module of the same package +``` + +The part before `/` is the package name, and the part after it is the module inside it. This way a single package can bundle many modules grouped by task. + +## package.json + +A package describes itself in a `package.json` file. It specifies the name, the dependencies, and which modules the package exposes: + +```json +{ + "name": "hexlet-basics", + "dependencies": {}, + "exports": { + "./string": "./src/hexlet/string.js", + "./math": "./src/hexlet/math.js" + } +} +``` + +The `exports` field defines which paths are available on import. Thanks to it, writing `hexlet-basics/string` resolves to the right file inside the package. + +## node_modules and the npm registry + +Installed packages end up in the `node_modules` directory. You don't write them by hand — the main source is the npm registry, where hundreds of thousands of ready-made packages are published: for working with dates, networking, testing, and almost any other task. + +Node.js built-in modules (`node:fs`, `node:path`, and others) stand apart. You don't need to install them — they ship with Node.js, like a standard library. diff --git a/modules/40-define-functions/470-packages/en/data.yml b/modules/40-define-functions/470-packages/en/data.yml new file mode 100644 index 00000000..c3b621d7 --- /dev/null +++ b/modules/40-define-functions/470-packages/en/data.yml @@ -0,0 +1,5 @@ +--- +name: Packages +tips: + - | + [About packages and modules in npm](https://docs.npmjs.com/about-packages-and-modules) diff --git a/modules/40-define-functions/470-packages/es/EXERCISE.md b/modules/40-define-functions/470-packages/es/EXERCISE.md new file mode 100644 index 00000000..0bff65c9 --- /dev/null +++ b/modules/40-define-functions/470-packages/es/EXERCISE.md @@ -0,0 +1,14 @@ +Implementa la función `formatPrice()`. Recibe un número y devuelve su representación como cadena, redondeada a dos decimales. + +Usa la función `round()` del módulo `hexlet-basics/math` — es otro módulo del mismo paquete `hexlet-basics` con el que trabajaste en la lección anterior. Escribe la importación tú mismo. + +```javascript +formatPrice(12.3456); // => '12.35' +formatPrice(2.5); // => '2.50' +formatPrice(10); // => '10.00' +``` + +## Pista + +* Al comienzo del archivo, importa la función: `import { round } from 'hexlet-basics/math';` +* El segundo argumento de `round()` es la cantidad de decimales diff --git a/modules/40-define-functions/470-packages/es/README.md b/modules/40-define-functions/470-packages/es/README.md new file mode 100644 index 00000000..a0fcd289 --- /dev/null +++ b/modules/40-define-functions/470-packages/es/README.md @@ -0,0 +1,51 @@ +A medida que un programa crece, no solo aumenta la cantidad de líneas de código, sino también la cantidad de módulos. En proyectos pequeños se pueden mantener decenas de archivos uno al lado del otro, pero las aplicaciones reales pueden tener cientos y miles de archivos. Además, el código útil se quiere reutilizar en distintos proyectos. + +En Python se usan los paquetes-directorios para agrupar módulos. En el ecosistema de JavaScript, la unidad de reutilización y distribución es un **paquete** (un paquete de npm). Un paquete es un conjunto de módulos que se publica y se instala como un todo. + +## Qué es un paquete + +Un paquete se describe con un archivo `package.json` y se instala con el comando `npm install` en el directorio `node_modules`. Desde ahí se importan sus módulos. Uno de esos paquetes es `hexlet-basics`, del que importamos funciones en este curso. + +## Importación por nombre del paquete + +Cuando un paquete está instalado, su contenido se importa por el nombre del paquete y no por la ruta a un archivo: + +```javascript +import { round } from 'hexlet-basics/math'; + +console.log(round(3.14159, 2)); // => 3.14 +``` + +## Un paquete, varios módulos + +Un paquete suele contener más de un módulo. Para elegir un módulo concreto dentro de un paquete, se añade una ruta tras su nombre con `/`: + +```javascript +import { reverse } from 'hexlet-basics/string'; // el módulo string del paquete hexlet-basics +import { round } from 'hexlet-basics/math'; // el módulo math del mismo paquete +``` + +La parte antes de `/` es el nombre del paquete, y la parte posterior es el módulo dentro de él. Así, un mismo paquete puede agrupar muchos módulos organizados por tarea. + +## package.json + +Un paquete se describe a sí mismo en un archivo `package.json`. En él se indican el nombre, las dependencias y qué módulos entrega al exterior: + +```json +{ + "name": "hexlet-basics", + "dependencies": {}, + "exports": { + "./string": "./src/hexlet/string.js", + "./math": "./src/hexlet/math.js" + } +} +``` + +El campo `exports` define qué rutas están disponibles al importar. Gracias a él, escribir `hexlet-basics/string` apunta al archivo correcto dentro del paquete. + +## node_modules y el registro de npm + +Los paquetes instalados acaban en el directorio `node_modules`. No se escriben a mano — la fuente principal es el registro de npm, donde hay publicados cientos de miles de paquetes listos para usar: para trabajar con fechas, redes, pruebas y casi cualquier otra tarea. + +Aparte están los módulos integrados del entorno Node.js (`node:fs`, `node:path` y otros). No hace falta instalarlos — vienen junto con Node.js, como una biblioteca estándar. diff --git a/modules/40-define-functions/470-packages/es/data.yml b/modules/40-define-functions/470-packages/es/data.yml new file mode 100644 index 00000000..0c28804e --- /dev/null +++ b/modules/40-define-functions/470-packages/es/data.yml @@ -0,0 +1,5 @@ +--- +name: Paquetes +tips: + - | + [Sobre paquetes y módulos en npm](https://docs.npmjs.com/about-packages-and-modules) diff --git a/modules/40-define-functions/470-packages/index.js b/modules/40-define-functions/470-packages/index.js new file mode 100644 index 00000000..ca4e2fe7 --- /dev/null +++ b/modules/40-define-functions/470-packages/index.js @@ -0,0 +1,7 @@ +// BEGIN +import { round } from 'hexlet-basics/math'; + +const formatPrice = (amount) => round(amount, 2); +// END + +export default formatPrice; diff --git a/modules/40-define-functions/470-packages/ru/EXERCISE.md b/modules/40-define-functions/470-packages/ru/EXERCISE.md new file mode 100644 index 00000000..934d176a --- /dev/null +++ b/modules/40-define-functions/470-packages/ru/EXERCISE.md @@ -0,0 +1,14 @@ +Реализуйте функцию `formatPrice()`. Она принимает число и возвращает его строковое представление, округлённое до двух знаков после запятой. + +Используйте функцию `round()` из модуля `hexlet-basics/math` — это другой модуль того же пакета `hexlet-basics`, с которым вы работали в прошлом уроке. Импорт напишите самостоятельно. + +```javascript +formatPrice(12.3456); // => '12.35' +formatPrice(2.5); // => '2.50' +formatPrice(10); // => '10.00' +``` + +## Подсказка + +* В начале файла импортируйте функцию: `import { round } from 'hexlet-basics/math';` +* Второй аргумент `round()` — количество знаков после запятой diff --git a/modules/40-define-functions/470-packages/ru/README.md b/modules/40-define-functions/470-packages/ru/README.md new file mode 100644 index 00000000..44e8d9d5 --- /dev/null +++ b/modules/40-define-functions/470-packages/ru/README.md @@ -0,0 +1,51 @@ +По мере роста программы увеличивается не только количество строк кода, но и количество модулей. В небольших проектах десятки файлов ещё можно держать рядом, но в реальных приложениях файлов могут быть сотни и тысячи. Кроме того, удобный код хочется переиспользовать в разных проектах. + +В Python для группировки модулей используют пакеты-директории. В экосистеме JavaScript единицей переиспользования и распространения служит **пакет** (npm-пакет). Пакет — это набор модулей, который публикуют и устанавливают целиком. + +## Что такое пакет + +Пакет описывается файлом `package.json` и устанавливается командой `npm install` в директорию `node_modules`. Именно оттуда подключаются его модули. Один из таких пакетов — `hexlet-basics`, из которого мы импортируем функции в этом курсе. + +## Импорт по имени пакета + +Когда пакет установлен, его содержимое импортируют по имени пакета, а не по пути к файлу: + +```javascript +import { round } from 'hexlet-basics/math'; + +console.log(round(3.14159, 2)); // => 3.14 +``` + +## Один пакет — несколько модулей + +Пакет обычно содержит не один модуль, а несколько. Чтобы выбрать конкретный модуль внутри пакета, после его имени указывают путь через `/`: + +```javascript +import { reverse } from 'hexlet-basics/string'; // модуль string пакета hexlet-basics +import { round } from 'hexlet-basics/math'; // модуль math того же пакета +``` + +Часть до `/` — это имя пакета, а часть после — модуль внутри него. Так один пакет может объединять много модулей, сгруппированных по задачам. + +## package.json + +Пакет сам описывает себя в файле `package.json`. В нём указывают имя, зависимости и то, какие модули пакет отдаёт наружу: + +```json +{ + "name": "hexlet-basics", + "dependencies": {}, + "exports": { + "./string": "./src/hexlet/string.js", + "./math": "./src/hexlet/math.js" + } +} +``` + +Поле `exports` задаёт, какие пути доступны при импорте. Благодаря ему запись `hexlet-basics/string` приводит к нужному файлу внутри пакета. + +## node_modules и реестр npm + +Установленные пакеты попадают в директорию `node_modules`. Их не пишут вручную — основным источником служит реестр npm, где опубликованы сотни тысяч готовых пакетов: для работы с датами, сетью, тестами и почти любой другой задачей. + +Особняком стоят встроенные модули среды Node.js (`node:fs`, `node:path` и другие). Их не нужно устанавливать — они поставляются вместе с Node.js, как стандартная библиотека. diff --git a/modules/40-define-functions/470-packages/ru/data.yml b/modules/40-define-functions/470-packages/ru/data.yml new file mode 100644 index 00000000..b5fb4829 --- /dev/null +++ b/modules/40-define-functions/470-packages/ru/data.yml @@ -0,0 +1,5 @@ +--- +name: Пакеты +tips: + - | + [О пакетах и модулях в npm](https://docs.npmjs.com/about-packages-and-modules) diff --git a/modules/40-define-functions/470-packages/test.js b/modules/40-define-functions/470-packages/test.js new file mode 100644 index 00000000..417627c5 --- /dev/null +++ b/modules/40-define-functions/470-packages/test.js @@ -0,0 +1,10 @@ +// @ts-check + +import { expect, test } from 'vitest'; +import formatPrice from './index.js'; + +test('formatPrice', () => { + expect(formatPrice(12.3456)).toBe('12.35'); + expect(formatPrice(2.5)).toBe('2.50'); + expect(formatPrice(10)).toBe('10.00'); +});