Skip to content

Commit 0191580

Browse files
committed
Make examples runnable, validate them with TypeScript and ESLint
1 parent 22841d2 commit 0191580

10 files changed

Lines changed: 150 additions & 39 deletions

‎eslint.config.mjs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import gnome from 'eslint-config-gnome';
1010

1111
export default defineConfig([
1212
{
13-
files: ['*.js', '*.mjs', 'tests/*.js'],
13+
files: ['*.js', '*.mjs', 'tests/*.js', 'examples/*.js'],
1414
plugins: {gnome},
1515
extends: ['gnome/recommended'],
1616
rules: {
@@ -42,8 +42,8 @@ export default defineConfig([
4242
files: [
4343
'ambient.d.ts',
4444
'gjs-typelib-installer.js',
45-
'tests/test.js',
46-
'tests/e2e-test.js',
45+
'tests/*.js',
46+
'examples/*.js',
4747
],
4848
plugins: {jsdoc, tseslint},
4949
extends: [
@@ -72,6 +72,7 @@ export default defineConfig([
7272
{
7373
files: [
7474
'tests/*.js',
75+
'examples/*.js',
7576
],
7677
plugins: {jsdoc},
7778
rules: {

‎examples/gtk4-pkg-name.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env -S gjs -m
2+
3+
// SPDX-FileCopyrightText: 2026 Aleksandr Mezin <mezin.alexander@gmail.com>
4+
//
5+
// SPDX-License-Identifier: MIT
6+
7+
import {packages} from '../gjs-typelib-installer.js';
8+
9+
// #region example
10+
const gtk = packages.Gtk['4.0']().packages;
11+
12+
if (gtk)
13+
print(`To install Gtk 4.0 typelib, install the following package(s): ${gtk.join(', ')}`);
14+
else
15+
printerr("Can't find a Gtk 4.0 package for this OS");
16+
// #endregion example

‎examples/install-template.js‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env -S gjs -m
2+
3+
// SPDX-FileCopyrightText: 2026 Aleksandr Mezin <mezin.alexander@gmail.com>
4+
//
5+
// SPDX-License-Identifier: MIT
6+
7+
import System from 'system';
8+
import GLib from 'gi://GLib';
9+
10+
import {require, findTerminalInstallCommand, MissingDependencies} from '../gjs-typelib-installer.js';
11+
12+
// #region example
13+
/** @import TemplateMod from '@girs/template-1.0' */
14+
15+
try {
16+
const {Template} = /** @type {{Template: TemplateMod}} */ (require({Template: '1.0'}));
17+
18+
const t = Template.Template.new(null);
19+
t.parse_string('2 + 2 = {{ 2 + 2 }}');
20+
print(t.expand_string(null));
21+
} catch (ex) {
22+
if (!(ex instanceof MissingDependencies))
23+
throw ex;
24+
25+
// For simplicity, we start the installation process immediately here.
26+
// But usually it's a good idea to have an "Install" button that the user can click,
27+
// or ask for confirmation.
28+
29+
const installer = await findTerminalInstallCommand();
30+
31+
if (!installer) {
32+
printerr("Can't install packages");
33+
System.exit(1);
34+
}
35+
36+
if (ex.packages.size === 0) {
37+
printerr("Can't find a package with Template-GLib for this OS");
38+
System.exit(1);
39+
}
40+
41+
const argv = installer(ex.packages);
42+
const [, pid] = GLib.spawn_async(null, argv, null, GLib.SpawnFlags.DEFAULT, null);
43+
GLib.spawn_close_pid(/** @type {GLib.Pid} */ (pid));
44+
45+
// Note: there's no reliable way to wait for package installation to complete.
46+
// Exit with an error, and ask the user to restart the app/enable the extension again.
47+
printerr('Please, try again after installing the package');
48+
System.exit(1);
49+
}
50+
// #endregion example

‎examples/require-template.js‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env -S gjs -m
2+
3+
// SPDX-FileCopyrightText: 2026 Aleksandr Mezin <mezin.alexander@gmail.com>
4+
//
5+
// SPDX-License-Identifier: MIT
6+
7+
import {require, MissingDependencies} from '../gjs-typelib-installer.js';
8+
9+
// #region example
10+
/** @import TemplateMod from '@girs/template-1.0' */
11+
12+
try {
13+
const {Template} = /** @type {{Template: TemplateMod}} */ (require({Template: '1.0'}));
14+
15+
const t = Template.Template.new(null);
16+
t.parse_string('2 + 2 = {{ 2 + 2 }}');
17+
print(t.expand_string(null));
18+
} catch (ex) {
19+
if (!(ex instanceof MissingDependencies))
20+
throw ex;
21+
22+
if (ex.packages.size > 0)
23+
printerr(`Please install the packages: ${[...ex.packages].join(', ')}`);
24+
25+
if (ex.files.size > 0)
26+
printerr(`Please install packages that contain the files: ${[...ex.files].join(', ')}`);
27+
}
28+
// #endregion example

‎examples/terminal-hello.js‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env -S gjs -m
2+
3+
// SPDX-FileCopyrightText: 2026 Aleksandr Mezin <mezin.alexander@gmail.com>
4+
//
5+
// SPDX-License-Identifier: MIT
6+
7+
import GLib from 'gi://GLib';
8+
9+
import {findTerminalCommand} from '../gjs-typelib-installer.js';
10+
11+
// #region example
12+
const terminal = await findTerminalCommand();
13+
14+
if (terminal) {
15+
const argv = terminal(['echo', 'Hello, world!']);
16+
const [, pid] = GLib.spawn_async(null, argv, null, GLib.SpawnFlags.DEFAULT, null);
17+
GLib.spawn_close_pid(/** @type {GLib.Pid} */ (pid));
18+
} else {
19+
printerr('No terminal emulators found');
20+
}
21+
// #endregion example

‎gjs-typelib-installer.js‎

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ function resolveByOsId(filename, distros) {
123123
* Organized by namespace and version, each entry maps to a resolver function
124124
* that returns the appropriate package names for the current OS.
125125
*
126-
* @example <caption>Get the package name for Gtk 4.0 on the current OS</caption>
127-
* packages.Gtk['4.0']().packages
126+
* @example Get the package name for Gtk 4.0 on the current OS
127+
* {@includeCode examples/gtk4-pkg-name.js#example}
128128
*/
129129
export const packages = {
130130
Adw: {
@@ -300,20 +300,8 @@ export class MissingDependencies extends Error {
300300
* {@link MissingDependencies}.
301301
* @throws {Error} If an unknown library is requested.
302302
*
303-
* @example <caption>Import 'gi://Handy?version=1' or ask the user to install packages</caption>
304-
* try {
305-
* const {Handy} = require({Handy: '1'});
306-
* // ...
307-
* } catch (ex) {
308-
* if (!(ex instanceof MissingDependencies))
309-
* throw ex;
310-
*
311-
* if (ex.packages.size > 0)
312-
* printerr(`Please install the packages: ${[...ex.packages]}`);
313-
*
314-
* if (ex.files.size > 0)
315-
* printerr(`Please install the packages that contain the files: ${[...ex.files]}`);
316-
* }
303+
* @example Import Template-GLib or ask the user to install packages
304+
* {@includeCode examples/require-template.js#example}
317305
*/
318306
export function require(versions) {
319307
/** @type {Partial<Record<string, any>>} */
@@ -648,6 +636,9 @@ export async function findInstallCommand(cancellable = null) {
648636
* @param {Gio.Cancellable|null} cancellable - Optional cancellable for aborting the operation.
649637
* @returns {Promise<TerminalCommandResolver|null>} A function that generates
650638
* the command line, or null if no suitable terminal is found.
639+
*
640+
* @example "Hello, World!" in a new terminal
641+
* {@includeCode examples/terminal-hello.js#example}
651642
*/
652643
// eslint-disable-next-line @typescript-eslint/require-await
653644
export async function findTerminalCommand(cancellable = null) {
@@ -682,23 +673,8 @@ export async function findTerminalCommand(cancellable = null) {
682673
* given the list of packages, generates the installation command,
683674
* wrapped for terminal execution, or null if no terminal or install command is found.
684675
*
685-
* @example <caption>Install Gtk 4 package in a separate terminal window</caption>
686-
* findTerminalInstallCommand().then(installer => {
687-
* if (!installer) {
688-
* printerr("Can't install packages");
689-
* return;
690-
* }
691-
*
692-
* const pkgs = packages.Gtk['4.0']().packages;
693-
* if (!pkgs) {
694-
* printerr("Can't find a Gtk 4.0 package for this OS");
695-
* return;
696-
* }
697-
*
698-
* const argv = installer(pkgs);
699-
* const [, pid] = GLib.spawn_async(null, argv, null, GLib.SpawnFlags.DEFAULT, null);
700-
* GLib.spawn_close_pid(pid);
701-
* });
676+
* @example Install Template-GLib package in a separate terminal window
677+
* {@includeCode examples/install-template.js#example}
702678
*/
703679
export async function findTerminalInstallCommand(cancellable = null) {
704680
cancellable?.set_error_if_cancelled();

‎package-lock.json‎

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"@girs/girepository-2.0": "5.4.0",
2222
"@girs/girepository-3.0": "5.4.0",
2323
"@girs/gjs": "5.4.0",
24+
"@girs/template-1.0": "5.4.0",
2425
"eslint": "10.11.0",
2526
"eslint-config-gnome": "https://github.com/ddterm/eslint-config-gnome/archive/c479d059e8d9ea99c3b53c2ea43abf7fdb05eb51.tar.gz",
2627
"eslint-plugin-jsdoc": "65.0.0",

‎tsconfig.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
],
1919
},
2020
"include": [
21-
"eslint.config.mjs",
2221
"ambient.d.ts",
22+
"eslint.config.mjs",
2323
"gjs-typelib-installer.js",
24-
"tests/test.js",
25-
"tests/e2e-test.js",
24+
"tests/*.js",
25+
"examples/*.js",
2626
],
2727
}

‎typedoc.jsonc‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@
99
"name": "gjs-typelib-installer",
1010
"tsconfig": "tsconfig.json",
1111
"plugin": ["typedoc-plugin-mdn-links"],
12+
"jsDocCompatibility": {
13+
"exampleTag": false
14+
}
1215
}

0 commit comments

Comments
 (0)