Skip to content

Commit 4db2f6b

Browse files
authored
Merge pull request #29 from zapta/main
Added the command `demo project`, increased version to 0.1.3, some refactoring.
2 parents 1cbd126 + ff31fd5 commit 4db2f6b

19 files changed

Lines changed: 542 additions & 465 deletions

File tree

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
*.vsix
22
node_modules
33
.DS_Store
4-
eslint.config.mjs
54
.run.sh
65

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// eslint.config.mjs
2+
import globals from "globals";
3+
4+
export default [
5+
{
6+
languageOptions: {
7+
ecmaVersion: 2022,
8+
sourceType: "module",
9+
globals: {
10+
...globals.node,
11+
require: false, // Explicitly disallow require (overrides globals.node)
12+
module: false, // Disallow module.exports for consistency
13+
vscode: "readonly"
14+
}
15+
},
16+
rules: {
17+
"camelcase": "warn",
18+
"no-underscore-dangle": "off",
19+
"no-console": "off",
20+
"no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
21+
"semi": ["warn", "always"]
22+
}
23+
}
24+
];

apio-log.js

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
// apio-log.js
22
// Centralized logging for the Apio extension.
33

4-
"use strict";
54

6-
const vscode = require("vscode");
5+
import * as vscode from "vscode";
76

87
let outputChannel = null;
98

109
// Initializes the Apio output channel and push it to the extension context.
1110
// Must be called **once** from `activate(context)`.
1211
// @param {vscode.ExtensionContext} context
13-
function init(context) {
12+
export function init(context) {
1413
if (outputChannel) {
1514
return; // already initialized
1615
}
@@ -22,7 +21,7 @@ function init(context) {
2221
// Append a message to the Apio output channel.
2322
// @param {string} line Message to log
2423
// @param {boolean} [show=false] If true, the channel is shown (preserves focus)
25-
function msg(line, show = false) {
24+
export function msg(line, show = false) {
2625
if (!outputChannel) {
2726
// Fallback: create a temporary channel if initLog was never called.
2827
// This should never happen in normal operation.
@@ -37,14 +36,8 @@ function msg(line, show = false) {
3736
}
3837

3938
// Explicitly show the Apio output channel (preserves focus).
40-
function showChannel() {
39+
export function showChannel() {
4140
if (outputChannel) {
4241
outputChannel.show(true);
4342
}
4443
}
45-
46-
module.exports = {
47-
init,
48-
msg,
49-
showChannel,
50-
};

commands.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
// dict object. We use it to extract and register commands,
33
// sidebar view entries, and status bar buttons.
44

5-
"use strict";
6-
7-
const utils = require("./utils.js");
5+
import * as utils from "./utils.js";
86

97
// Commands for the PROJECT view. Thee commands are used only
108
// in the PROJECT mode and always have an open workspace and
119
// an apio.ini file.
12-
const PROJECT_TREE = [
10+
export const PROJECT_TREE = [
1311
{
1412
title: "make",
1513
children: [
@@ -86,10 +84,16 @@ const PROJECT_TREE = [
8684
// Commands for the TOOLS view. Thee commands are used only
8785
// in the PROJECT and NON_PROJECT mode and can't assume that a workspace
8886
// is open or that the project file apio.ini exist.
89-
const TOOLS_TREE = [
87+
export const TOOLS_TREE = [
9088
{
9189
title: "examples",
9290
children: [
91+
{
92+
title: "demo project",
93+
tooltip: "Play with a demo project",
94+
id: "apio.demoProject",
95+
// No action, implemented independently.
96+
},
9397
{
9498
title: "list examples",
9599
tooltip: "List project examples",
@@ -102,7 +106,9 @@ const TOOLS_TREE = [
102106
id: "apio.getExample",
103107
action: {
104108
cmds: [
105-
`{apio-bin} api get-examples -f -o ${utils.apioTmpFile("examples.json")}`,
109+
`{apio-bin} api get-examples -f -o ${utils.apioTmpChild(
110+
"examples.json"
111+
)}`,
106112
],
107113
cmdId: "apio.projectFromExample",
108114
},
@@ -262,7 +268,7 @@ const TOOLS_TREE = [
262268
},
263269
];
264270

265-
const HELP_TREE = [
271+
export const HELP_TREE = [
266272
{
267273
title: "documentation",
268274
children: [
@@ -322,6 +328,3 @@ const HELP_TREE = [
322328
],
323329
},
324330
];
325-
326-
// Exported symbols
327-
module.exports = { PROJECT_TREE, TOOLS_TREE, HELP_TREE };

constants.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,8 @@
66

77
// GitHub repository that hosts the pre-built Apio bundles
88
// https://github.com/FPGAwars/apio-dev-builds/releases
9-
const APIO_RELEASE_GITHUB_REPO = "FPGAwars/apio-dev-builds";
9+
export const APIO_RELEASE_GITHUB_REPO = "FPGAwars/apio-dev-builds";
1010

1111
// Release tag (YYYY-MM-DD) – matches git tag and PyPI version
1212
// Change ONLY this line when you publish a new daily build.
13-
const APIO_RELEASE_TAG = "2025-12-07";
14-
15-
// Export everything for require()
16-
module.exports = {
17-
APIO_RELEASE_GITHUB_REPO,
18-
APIO_RELEASE_TAG,
19-
};
13+
export const APIO_RELEASE_TAG = "2025-12-07";

downloader.js

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,25 @@
33
// the apio binary is available at ~/.apio/bin/apio[.exe]. If not,
44
// It's downloaded and installed on the fly.
55

6-
"use strict";
7-
86
// Standard imports
9-
const fs = require("fs");
10-
const path = require("path");
11-
const stream = require("node:stream");
12-
const childProcess = require("child_process");
13-
const assert = require("node:assert");
7+
import * as fs from "fs";
8+
import * as path from "path";
9+
import * as stream from "node:stream";
10+
import * as childProcess from "child_process";
11+
12+
// Assert function.
13+
import assert from "node:assert";
1414

1515
// Dependency imports
16-
const zipExtract = require("extract-zip");
17-
const tar = require("tar");
16+
import * as zipExtract from "extract-zip";
17+
import * as tar from "tar";
1818

1919
// Local imports
20-
const constants = require("./constants.js");
21-
const platforms = require("./platforms.js");
22-
const apioLog = require("./apio-log.js");
23-
const jsonUtils = require("./json-utils.js");
24-
const utils = require("./utils.js");
20+
import * as constants from "./constants.js";
21+
import * as platforms from "./platforms.js";
22+
import * as apioLog from "./apio-log.js";
23+
import * as jsonUtils from "./json-utils.js";
24+
import * as utils from "./utils.js";
2525

2626
// Download url and local package name
2727
const downloadMetadataFileName = "download-metadata.json";
@@ -30,7 +30,7 @@ let _downloadDstFilePath = null;
3030

3131
// Initializes this module. Should be called once before any other
3232
// function of this module.
33-
function init() {
33+
export function init() {
3434
// Should be called only once.
3535
assert(
3636
_downloadSrcUrl == null,
@@ -53,33 +53,41 @@ function init() {
5353
}
5454

5555
// Ensures the Apio binary is ready and if not download and installs it.
56-
// @returns {Promise<string>} that govern the downloading.
57-
async function ensureApioBinary() {
58-
// Check if the apio binary exists.
59-
const binaryExists = await _testFsItem(
60-
utils.apioBinaryPath(),
61-
fs.constants.X_OK | fs.constants.R_OK
62-
);
63-
apioLog.msg(`Apio binary ${utils.apioBinaryPath()} exists = ${binaryExists}`);
64-
65-
// Check if the download metadata has a matching download url
66-
const metadataFilePath = path.join(
67-
utils.apioBinDir(),
68-
downloadMetadataFileName
69-
);
70-
// 'metadata' is {} if file doesn't exist or any error.
71-
const metadataDict = await jsonUtils.readJson(metadataFilePath);
72-
const lastUrl = metadataDict.url ?? null;
73-
const urlMatches = lastUrl == _downloadSrcUrl;
74-
apioLog.msg(`Download url match = ${urlMatches}`);
75-
76-
if (binaryExists && urlMatches) {
77-
// Binary is good, will use it.
78-
apioLog.msg(`Existing binary ok: ${utils.apioBinaryPath()}`);
79-
} else {
80-
// Binary is missing or not good, will download and install it.
81-
apioLog.msg("Need to download and install a new binary.");
82-
await _downloadAndInstall();
56+
// Throws an exception if failed.
57+
export async function ensureApioBinary() {
58+
try {
59+
// Check if the apio binary exists.
60+
const binaryExists = await _testFsItem(
61+
utils.apioBinaryPath(),
62+
fs.constants.X_OK | fs.constants.R_OK
63+
);
64+
apioLog.msg(
65+
`Apio binary ${utils.apioBinaryPath()} exists = ${binaryExists}`
66+
);
67+
68+
// Check if the download metadata has a matching download url
69+
const metadataFilePath = path.join(
70+
utils.apioBinDir(),
71+
downloadMetadataFileName
72+
);
73+
// 'metadata' is {} if file doesn't exist or any error.
74+
const metadataDict = await jsonUtils.readJson(metadataFilePath);
75+
const lastUrl = metadataDict.url ?? null;
76+
const urlMatches = lastUrl == _downloadSrcUrl;
77+
apioLog.msg(`Download url match = ${urlMatches}`);
78+
79+
if (binaryExists && urlMatches) {
80+
// Binary is good, will use it.
81+
apioLog.msg(`Existing binary ok: ${utils.apioBinaryPath()}`);
82+
} else {
83+
// Binary is missing or not good, will download and install it.
84+
apioLog.msg("Need to download and install a new binary.");
85+
await _downloadAndInstall();
86+
apioLog.msg(`[Apio] Binary installed: ${utils.apioBinaryPath()}`);
87+
}
88+
} catch (err) {
89+
// Handle errors, we wrap with 'Apio' message and throw again.
90+
throw Error(`[Apio] binary installation failed: ${err.message}`);
8391
}
8492
}
8593

@@ -224,6 +232,3 @@ async function _testFsItem(path, mode = fs.constants.F_OK) {
224232
return false;
225233
}
226234
}
227-
228-
// Exported functions.
229-
module.exports = { init, ensureApioBinary };

eslint.config.js

Lines changed: 0 additions & 24 deletions
This file was deleted.

eslint.config.mjs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// eslint.config.mjs
2+
3+
export default [
4+
{
5+
languageOptions: {
6+
ecmaVersion: 2022,
7+
sourceType: "module",
8+
globals: {
9+
process: "readonly",
10+
console: "readonly",
11+
__dirname: "readonly",
12+
__filename: "readonly",
13+
Buffer: "readonly",
14+
global: "readonly",
15+
vscode: "readonly",
16+
},
17+
},
18+
rules: {
19+
camelcase: "warn",
20+
"no-underscore-dangle": "off",
21+
"no-console": "off",
22+
"no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
23+
semi: ["warn", "always"],
24+
},
25+
},
26+
];

0 commit comments

Comments
 (0)