thinkinglanguage 0.1.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.
Files changed (3) hide show
  1. package/bin/tl +23 -0
  2. package/install.js +160 -0
  3. package/package.json +28 -0
package/bin/tl ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { execFileSync } = require("child_process");
5
+ const path = require("path");
6
+ const os = require("os");
7
+ const fs = require("fs");
8
+
9
+ const binName = os.platform() === "win32" ? "tl.exe" : "tl";
10
+ const binPath = path.join(__dirname, binName);
11
+
12
+ if (!fs.existsSync(binPath)) {
13
+ console.error(
14
+ "tl binary not found. Run 'npm install' or 'node install.js' to download it."
15
+ );
16
+ process.exit(1);
17
+ }
18
+
19
+ try {
20
+ execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
21
+ } catch (err) {
22
+ process.exit(err.status || 1);
23
+ }
package/install.js ADDED
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { execSync } = require("child_process");
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+ const https = require("https");
8
+ const os = require("os");
9
+ const zlib = require("zlib");
10
+
11
+ const VERSION = `v${require("./package.json").version}`;
12
+ const REPO = "mplusm/thinkinglanguage";
13
+ const BIN_DIR = path.join(__dirname, "bin");
14
+ const BIN_PATH = path.join(BIN_DIR, os.platform() === "win32" ? "tl.exe" : "tl");
15
+
16
+ function getPlatformTarget() {
17
+ const platform = os.platform();
18
+ const arch = os.arch();
19
+
20
+ if (platform === "linux" && arch === "x64") {
21
+ return "x86_64-unknown-linux-gnu";
22
+ }
23
+ if (platform === "darwin" && arch === "arm64") {
24
+ return "aarch64-apple-darwin";
25
+ }
26
+ if (platform === "win32" && arch === "x64") {
27
+ return "x86_64-pc-windows-msvc";
28
+ }
29
+
30
+ throw new Error(
31
+ `Unsupported platform: ${platform}-${arch}. ` +
32
+ `Download manually from https://github.com/${REPO}/releases`
33
+ );
34
+ }
35
+
36
+ function fetch(url) {
37
+ return new Promise((resolve, reject) => {
38
+ https
39
+ .get(url, { headers: { "User-Agent": "thinkinglanguage-npm" } }, (res) => {
40
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
41
+ return fetch(res.headers.location).then(resolve, reject);
42
+ }
43
+ if (res.statusCode !== 200) {
44
+ return reject(new Error(`HTTP ${res.statusCode} for ${url}`));
45
+ }
46
+ const chunks = [];
47
+ res.on("data", (c) => chunks.push(c));
48
+ res.on("end", () => resolve(Buffer.concat(chunks)));
49
+ res.on("error", reject);
50
+ })
51
+ .on("error", reject);
52
+ });
53
+ }
54
+
55
+ function extractTarGz(buffer, destDir, binaryName) {
56
+ // tar.gz: gzip layer then POSIX tar (512-byte header blocks)
57
+ const tar = zlib.gunzipSync(buffer);
58
+ let offset = 0;
59
+ while (offset < tar.length) {
60
+ const header = tar.subarray(offset, offset + 512);
61
+ if (header.every((b) => b === 0)) break;
62
+
63
+ const name = header.toString("utf8", 0, 100).replace(/\0.*/g, "");
64
+ const sizeStr = header.toString("utf8", 124, 136).replace(/\0.*/g, "").trim();
65
+ const size = parseInt(sizeStr, 8) || 0;
66
+ const dataStart = offset + 512;
67
+
68
+ if (name === binaryName || name.endsWith(`/${binaryName}`)) {
69
+ const data = tar.subarray(dataStart, dataStart + size);
70
+ const dest = path.join(destDir, binaryName);
71
+ fs.writeFileSync(dest, data);
72
+ fs.chmodSync(dest, 0o755);
73
+ return true;
74
+ }
75
+
76
+ offset = dataStart + Math.ceil(size / 512) * 512;
77
+ }
78
+ return false;
79
+ }
80
+
81
+ function extractZip(buffer, destDir, binaryName) {
82
+ // Find the file in the zip by scanning for local file headers
83
+ let offset = 0;
84
+ while (offset < buffer.length - 4) {
85
+ // Local file header signature: 0x04034b50
86
+ if (
87
+ buffer[offset] === 0x50 &&
88
+ buffer[offset + 1] === 0x4b &&
89
+ buffer[offset + 2] === 0x03 &&
90
+ buffer[offset + 3] === 0x04
91
+ ) {
92
+ const nameLen = buffer.readUInt16LE(offset + 26);
93
+ const extraLen = buffer.readUInt16LE(offset + 28);
94
+ const compSize = buffer.readUInt32LE(offset + 18);
95
+ const uncompSize = buffer.readUInt32LE(offset + 22);
96
+ const compressionMethod = buffer.readUInt16LE(offset + 8);
97
+ const name = buffer.toString("utf8", offset + 30, offset + 30 + nameLen);
98
+ const dataStart = offset + 30 + nameLen + extraLen;
99
+
100
+ if (name === binaryName || name.endsWith(`/${binaryName}`) || name.endsWith(`\\${binaryName}`)) {
101
+ let data;
102
+ if (compressionMethod === 0) {
103
+ data = buffer.subarray(dataStart, dataStart + uncompSize);
104
+ } else if (compressionMethod === 8) {
105
+ data = zlib.inflateRawSync(buffer.subarray(dataStart, dataStart + compSize));
106
+ } else {
107
+ throw new Error(`Unsupported zip compression method: ${compressionMethod}`);
108
+ }
109
+ const dest = path.join(destDir, binaryName);
110
+ fs.writeFileSync(dest, data);
111
+ fs.chmodSync(dest, 0o755);
112
+ return true;
113
+ }
114
+
115
+ offset = dataStart + compSize;
116
+ } else {
117
+ offset++;
118
+ }
119
+ }
120
+ return false;
121
+ }
122
+
123
+ async function main() {
124
+ if (fs.existsSync(BIN_PATH)) {
125
+ console.log(`tl binary already exists at ${BIN_PATH}`);
126
+ return;
127
+ }
128
+
129
+ const target = getPlatformTarget();
130
+ const isWindows = os.platform() === "win32";
131
+ const ext = isWindows ? "zip" : "tar.gz";
132
+ const archive = `tl-${target}.${ext}`;
133
+ const url = `https://github.com/${REPO}/releases/download/${VERSION}/${archive}`;
134
+
135
+ console.log(`Downloading tl ${VERSION} for ${target}...`);
136
+ const buffer = await fetch(url);
137
+
138
+ fs.mkdirSync(BIN_DIR, { recursive: true });
139
+
140
+ const binaryName = isWindows ? "tl.exe" : "tl";
141
+
142
+ console.log("Extracting...");
143
+ let found;
144
+ if (isWindows) {
145
+ found = extractZip(buffer, BIN_DIR, binaryName);
146
+ } else {
147
+ found = extractTarGz(buffer, BIN_DIR, binaryName);
148
+ }
149
+
150
+ if (!found) {
151
+ throw new Error(`Could not find ${binaryName} in downloaded archive`);
152
+ }
153
+
154
+ console.log(`Installed tl to ${BIN_PATH}`);
155
+ }
156
+
157
+ main().catch((err) => {
158
+ console.error(`Failed to install tl: ${err.message}`);
159
+ process.exit(1);
160
+ });
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "thinkinglanguage",
3
+ "version": "0.1.0",
4
+ "description": "A purpose-built language for Data Engineering & AI",
5
+ "license": "MIT OR Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/mplusm/thinkinglanguage"
9
+ },
10
+ "homepage": "https://github.com/mplusm/thinkinglanguage",
11
+ "keywords": [
12
+ "data-engineering",
13
+ "language",
14
+ "ai",
15
+ "pipeline",
16
+ "etl"
17
+ ],
18
+ "bin": {
19
+ "tl": "bin/tl"
20
+ },
21
+ "scripts": {
22
+ "postinstall": "node install.js"
23
+ },
24
+ "files": [
25
+ "bin/",
26
+ "install.js"
27
+ ]
28
+ }