dew 0.1.0 → 0.7.31
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 +157 -10
- package/bin/dew +212 -20
- package/package.json +12 -26
- package/.jshintrc +0 -13
- package/.npmignore +0 -27
- package/.travis.yml +0 -3
- package/LICENSE +0 -21
- package/bin/detest +0 -10
- package/bin/undew +0 -10
- package/lib/detest.js +0 -25
- package/lib/dew/buildFile/makeCoffee.js +0 -11
- package/lib/dew/buildFile/makeJS.js +0 -11
- package/lib/dew/buildFiles.js +0 -39
- package/lib/dew/buildTest/coffeeTest.js +0 -17
- package/lib/dew/buildTest/jsTest.js +0 -18
- package/lib/dew/index.js +0 -24
- package/lib/dew/utility/getExt.js +0 -30
- package/lib/dew/utility/parseInput.js +0 -49
- package/lib/undew.js +0 -24
package/README.md
CHANGED
|
@@ -1,19 +1,166 @@
|
|
|
1
|
-
|
|
2
|
-
====
|
|
1
|
+
# Dew
|
|
3
2
|
|
|
3
|
+
[](https://github.com/solcreek/dew/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/solcreek/dew/releases/latest)
|
|
5
|
+
[](https://www.npmjs.com/package/dew)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
Sandboxed Linux compute, agent-native and human-friendly.
|
|
9
|
+
|
|
10
|
+
Boot a real Linux environment locally. Drive it from a shell, a script,
|
|
11
|
+
or an agent.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
$ dew up
|
|
15
|
+
detected: vite (npm)
|
|
16
|
+
✓ http://localhost:5173
|
|
17
|
+
|
|
18
|
+
$ dew exec --json "go test ./..."
|
|
19
|
+
{"stdout":"PASS\nok ./...","exitCode":0}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# macOS / Linux
|
|
26
|
+
curl -fsSL https://dewvm.dev/install.sh | sh
|
|
27
|
+
|
|
28
|
+
# macOS Homebrew
|
|
29
|
+
brew install solcreek/tap/dew
|
|
30
|
+
|
|
31
|
+
# npm (all platforms)
|
|
32
|
+
npm install -g dew
|
|
33
|
+
|
|
34
|
+
# Windows (PowerShell)
|
|
35
|
+
irm https://github.com/solcreek/dew/releases/latest/download/install.ps1 | iex
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Then try:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
dew run -- uname -a
|
|
42
|
+
# (first time: downloads kernel + minimal initramfs, ~15s; then boots a
|
|
43
|
+
# real Linux VM and prints its uname)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## What it does
|
|
47
|
+
|
|
48
|
+
### Dev environments
|
|
49
|
+
|
|
50
|
+
Auto-detects your project and starts a dev environment with hot reload.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
cd my-vite-app
|
|
54
|
+
dew up # detect, boot, install, start
|
|
55
|
+
dew up --with postgres,redis # dev with services
|
|
56
|
+
dew down # stop
|
|
4
57
|
```
|
|
5
|
-
|
|
58
|
+
|
|
59
|
+
Supports: Vite, Next.js, Astro, Nuxt, SvelteKit, Django, Flask, FastAPI, static HTML.
|
|
60
|
+
|
|
61
|
+
### Share instantly
|
|
62
|
+
|
|
63
|
+
Temporary public HTTPS URL for any local port. Zero config, zero account.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
dew share 3000
|
|
67
|
+
✓ https://random-words.trycloudflare.com
|
|
68
|
+
Press Ctrl+C to stop
|
|
6
69
|
```
|
|
7
|
-
`dew` creates a file, tests for that file, and add it to other files dependencies (when specified, not yet impletemented).
|
|
8
70
|
|
|
9
|
-
|
|
71
|
+
### Deploy to a VPS
|
|
72
|
+
|
|
73
|
+
Build locally, deploy to any VPS. No extra runtime on the server.
|
|
10
74
|
|
|
11
|
-
|
|
12
|
-
|
|
75
|
+
```bash
|
|
76
|
+
dew build # package app (421KB tarball)
|
|
77
|
+
dew server create --provider hetzner # provision VPS ($5/mo)
|
|
78
|
+
dew deploy 5.161.53.168 # deploy with SSE progress
|
|
79
|
+
```
|
|
13
80
|
|
|
81
|
+
The server runs `dew serve` (7.1MB Linux binary) — containerd for isolation, self-signed TLS, health checks.
|
|
14
82
|
|
|
15
|
-
|
|
83
|
+
## Agent integration
|
|
84
|
+
|
|
85
|
+
Every command supports `--json` for machine-readable output and `--dry-run` for validation without execution.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
dew up --dry-run --json
|
|
89
|
+
# {"type":"dry-run","framework":"vite","profile":"node",...}
|
|
90
|
+
|
|
91
|
+
dew deploy prod --dry-run
|
|
92
|
+
# Would deploy my-app.tar.gz to https://prod:9080
|
|
93
|
+
# No changes made.
|
|
94
|
+
|
|
95
|
+
dew run --json -- npm test
|
|
96
|
+
# {"exit_code":0,"stdout":"5 passing\n"}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Input hardening: rejects path traversal, query injection, control characters. `--events` for NDJSON lifecycle streaming.
|
|
100
|
+
|
|
101
|
+
## Architecture
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
Local Linux server
|
|
105
|
+
───── ────────────
|
|
106
|
+
dew dew (deploy receiver)
|
|
107
|
+
├── dew up ├── HTTP deploy API
|
|
108
|
+
├── dew run ├── containers
|
|
109
|
+
├── dew exec ├── TLS
|
|
110
|
+
├── dew build ├── process management
|
|
111
|
+
├── dew deploy ──────────→ └── health check
|
|
112
|
+
└── Linux VM
|
|
113
|
+
└── containers inside
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Profiles
|
|
117
|
+
|
|
118
|
+
| Profile | Use case |
|
|
119
|
+
|---|---|
|
|
120
|
+
| minimal | Generic Linux shell, lightest footprint |
|
|
121
|
+
| node | Node.js / npm projects |
|
|
122
|
+
| python | Python projects |
|
|
123
|
+
| standard | Containers, services |
|
|
124
|
+
|
|
125
|
+
## Security
|
|
126
|
+
|
|
127
|
+
- Hardware-VM isolation. Network off until you flip `--network`. Input validated against path traversal, control characters, and injection.
|
|
128
|
+
|
|
129
|
+
## Full command reference
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
Dev:
|
|
133
|
+
dew up [dir] Start dev environment
|
|
134
|
+
dew up --with postgres,redis Dev with services
|
|
135
|
+
dew down Stop dev environment
|
|
136
|
+
|
|
137
|
+
Share:
|
|
138
|
+
dew share [port] Temporary public HTTPS URL
|
|
139
|
+
|
|
140
|
+
Deploy:
|
|
141
|
+
dew build [dir] Package app for deployment
|
|
142
|
+
dew deploy <target> Deploy to remote server
|
|
143
|
+
dew env ... Manage environment variables
|
|
144
|
+
dew auth ... Manage credentials
|
|
145
|
+
|
|
146
|
+
Infrastructure:
|
|
147
|
+
dew server create [--provider] Provision a VPS
|
|
148
|
+
dew server list List managed servers
|
|
149
|
+
dew server destroy <name> Remove a server
|
|
150
|
+
dew serve Run deploy receiver (VPS)
|
|
151
|
+
|
|
152
|
+
Advanced:
|
|
153
|
+
dew run [--] <cmd> Execute in ephemeral VM
|
|
154
|
+
dew exec <cmd> Execute in running VM
|
|
155
|
+
dew assets ... Manage VM images
|
|
156
|
+
dew update Update to latest version
|
|
157
|
+
|
|
158
|
+
Output:
|
|
159
|
+
--json Machine-readable JSON (all commands)
|
|
160
|
+
--events NDJSON lifecycle stream
|
|
161
|
+
--dry-run Validate without executing
|
|
162
|
+
```
|
|
16
163
|
|
|
17
|
-
|
|
164
|
+
## License
|
|
18
165
|
|
|
19
|
-
|
|
166
|
+
MIT
|
package/bin/dew
CHANGED
|
@@ -1,23 +1,215 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// Thin dispatcher for @solcreek/dew.
|
|
5
|
+
//
|
|
6
|
+
// First run downloads the matching native binary from the GitHub Release
|
|
7
|
+
// for this package version, verifies SHA256 against checksums.txt, and
|
|
8
|
+
// caches in DEW_CACHE_DIR. Subsequent runs spawn the cached binary directly.
|
|
9
|
+
//
|
|
10
|
+
// We don't ship the binary inside the npm package — it lives in
|
|
11
|
+
// goreleaser-produced tarballs on GH Releases. This keeps the npm tarball
|
|
12
|
+
// tiny (no binary bytes touched by npm install), avoids per-platform
|
|
13
|
+
// publish setups, and lets brew/install.sh/direct download all consume
|
|
14
|
+
// the same exact bytes from one canonical source.
|
|
15
|
+
//
|
|
16
|
+
// Override: DEW_BINARY=/path/to/dew for local builds and testing.
|
|
17
|
+
// Override: DEW_CACHE_DIR=/path overrides the cache location.
|
|
18
|
+
// Set DEW_VERIFY_COSIGN=1 to hard-require cosign signature verification.
|
|
19
|
+
|
|
20
|
+
const fs = require("fs");
|
|
21
|
+
const path = require("path");
|
|
22
|
+
const os = require("os");
|
|
23
|
+
const https = require("https");
|
|
24
|
+
const crypto = require("crypto");
|
|
25
|
+
const zlib = require("zlib");
|
|
26
|
+
const { spawnSync } = require("child_process");
|
|
27
|
+
const { pipeline } = require("stream/promises");
|
|
28
|
+
const { createWriteStream, createReadStream } = require("fs");
|
|
29
|
+
|
|
30
|
+
const pkg = require("../package.json");
|
|
31
|
+
const VERSION = pkg.version;
|
|
32
|
+
const REPO = "solcreek/dew";
|
|
33
|
+
|
|
34
|
+
const SUPPORTED = {
|
|
35
|
+
"darwin-arm64": { goos: "darwin", goarch: "arm64", binName: "dew" },
|
|
36
|
+
"darwin-x64": { goos: "darwin", goarch: "amd64", binName: "dew" },
|
|
37
|
+
"linux-x64": { goos: "linux", goarch: "amd64", binName: "dew" },
|
|
38
|
+
"linux-arm64": { goos: "linux", goarch: "arm64", binName: "dew" },
|
|
39
|
+
"win32-x64": { goos: "windows", goarch: "amd64", binName: "dew.exe" },
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function fatal(msg) {
|
|
43
|
+
process.stderr.write(`dew: ${msg}\n`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function cacheDir() {
|
|
48
|
+
if (process.env.DEW_CACHE_DIR) return process.env.DEW_CACHE_DIR;
|
|
49
|
+
const xdg = process.env.XDG_DATA_HOME;
|
|
50
|
+
const base = xdg || path.join(os.homedir(), ".local", "share");
|
|
51
|
+
return path.join(base, "dew", "bin", VERSION);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function get(url) {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
https.get(url, (res) => {
|
|
57
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
58
|
+
res.resume();
|
|
59
|
+
return resolve(get(res.headers.location));
|
|
60
|
+
}
|
|
61
|
+
if (res.statusCode !== 200) {
|
|
62
|
+
return reject(new Error(`HTTP ${res.statusCode} ${url}`));
|
|
63
|
+
}
|
|
64
|
+
resolve(res);
|
|
65
|
+
}).on("error", reject);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function downloadTo(url, destPath) {
|
|
70
|
+
const res = await get(url);
|
|
71
|
+
await pipeline(res, createWriteStream(destPath));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function fetchText(url) {
|
|
75
|
+
const res = await get(url);
|
|
76
|
+
let body = "";
|
|
77
|
+
for await (const chunk of res) body += chunk;
|
|
78
|
+
return body;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function sha256OfFile(p) {
|
|
82
|
+
const h = crypto.createHash("sha256");
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const s = createReadStream(p);
|
|
85
|
+
s.on("data", (d) => h.update(d));
|
|
86
|
+
s.on("end", () => resolve(h.digest("hex")));
|
|
87
|
+
s.on("error", reject);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Extract a single named file from a tar.gz with no native deps.
|
|
92
|
+
// Tar layout: 512-byte header, payload padded to 512.
|
|
93
|
+
function extractTarGz(archivePath, outDir, binName) {
|
|
94
|
+
const buf = zlib.gunzipSync(fs.readFileSync(archivePath));
|
|
95
|
+
let off = 0;
|
|
96
|
+
while (off + 512 <= buf.length) {
|
|
97
|
+
const header = buf.subarray(off, off + 512);
|
|
98
|
+
const nameRaw = header.subarray(0, 100).toString("utf8").replace(/\0.*$/, "");
|
|
99
|
+
if (!nameRaw) { off += 512; continue; }
|
|
100
|
+
const sizeOctal = header.subarray(124, 136).toString("utf8").replace(/[\0 ]+$/, "");
|
|
101
|
+
const size = parseInt(sizeOctal, 8) || 0;
|
|
102
|
+
const typeflag = String.fromCharCode(header[156]) || "0";
|
|
103
|
+
const dataStart = off + 512;
|
|
104
|
+
const dataEnd = dataStart + size;
|
|
105
|
+
if ((typeflag === "0" || typeflag === "") && path.basename(nameRaw) === binName) {
|
|
106
|
+
const dest = path.join(outDir, binName);
|
|
107
|
+
fs.writeFileSync(dest, buf.subarray(dataStart, dataEnd));
|
|
108
|
+
fs.chmodSync(dest, 0o755);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
off = dataEnd + (size % 512 === 0 ? 0 : 512 - (size % 512));
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function maybeVerifyCosign(dir, sumsBody) {
|
|
117
|
+
const verifyMode = process.env.DEW_VERIFY_COSIGN || "";
|
|
118
|
+
const cosignAvailable = spawnSync("cosign", ["version"], { stdio: "ignore" }).status === 0;
|
|
119
|
+
if (verifyMode !== "1" && !cosignAvailable) return;
|
|
120
|
+
|
|
121
|
+
const base = `https://github.com/${REPO}/releases/download/v${VERSION}`;
|
|
122
|
+
const sumsPath = path.join(dir, "checksums.txt");
|
|
123
|
+
const sigPath = path.join(dir, "checksums.txt.sig");
|
|
124
|
+
const pemPath = path.join(dir, "checksums.txt.pem");
|
|
125
|
+
fs.writeFileSync(sumsPath, sumsBody);
|
|
126
|
+
try {
|
|
127
|
+
await downloadTo(`${base}/checksums.txt.sig`, sigPath);
|
|
128
|
+
await downloadTo(`${base}/checksums.txt.pem`, pemPath);
|
|
129
|
+
} catch (e) {
|
|
130
|
+
if (verifyMode === "1") fatal(`cosign sig fetch failed: ${e.message}`);
|
|
131
|
+
process.stderr.write("dew: cosign verification skipped (signature absent)\n");
|
|
132
|
+
return;
|
|
22
133
|
}
|
|
134
|
+
const r = spawnSync("cosign", [
|
|
135
|
+
"verify-blob",
|
|
136
|
+
"--certificate", pemPath,
|
|
137
|
+
"--signature", sigPath,
|
|
138
|
+
"--certificate-identity-regexp",
|
|
139
|
+
`^https://github.com/${REPO}/\\.github/workflows/release\\.yml@refs/tags/v[0-9]+\\.[0-9]+\\.[0-9]+`,
|
|
140
|
+
"--certificate-oidc-issuer", "https://token.actions.githubusercontent.com",
|
|
141
|
+
sumsPath,
|
|
142
|
+
], { stdio: verifyMode === "1" ? "inherit" : "pipe" });
|
|
143
|
+
if (r.status !== 0) {
|
|
144
|
+
if (verifyMode === "1") fatal("cosign verification failed");
|
|
145
|
+
process.stderr.write("dew: cosign verification failed (continuing — set DEW_VERIFY_COSIGN=1 to enforce)\n");
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
process.stderr.write("dew: cosign verified\n");
|
|
23
149
|
}
|
|
150
|
+
|
|
151
|
+
async function ensureBinary() {
|
|
152
|
+
const triple = `${process.platform}-${process.arch}`;
|
|
153
|
+
const spec = SUPPORTED[triple];
|
|
154
|
+
if (!spec) {
|
|
155
|
+
fatal(
|
|
156
|
+
`${process.platform}/${process.arch} is not a supported platform.\n` +
|
|
157
|
+
`Supported: ${Object.keys(SUPPORTED).join(", ")}.\n` +
|
|
158
|
+
`If you have built dew from source, set DEW_BINARY=/path/to/dew.`,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const dir = cacheDir();
|
|
163
|
+
const binPath = path.join(dir, spec.binName);
|
|
164
|
+
if (fs.existsSync(binPath)) return binPath;
|
|
165
|
+
|
|
166
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
167
|
+
const tarName = `dew_${VERSION}_${spec.goos}_${spec.goarch}.tar.gz`;
|
|
168
|
+
const base = `https://github.com/${REPO}/releases/download/v${VERSION}`;
|
|
169
|
+
const tarUrl = `${base}/${tarName}`;
|
|
170
|
+
const sumUrl = `${base}/checksums.txt`;
|
|
171
|
+
const tarPath = path.join(dir, tarName);
|
|
172
|
+
|
|
173
|
+
process.stderr.write(`dew: downloading ${tarName}\n`);
|
|
174
|
+
try {
|
|
175
|
+
await downloadTo(tarUrl, tarPath);
|
|
176
|
+
} catch (e) {
|
|
177
|
+
fatal(`download failed: ${e.message}\n Set DEW_BINARY=/path/to/dew to bypass.`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
process.stderr.write(`dew: verifying checksum\n`);
|
|
181
|
+
let sums;
|
|
182
|
+
try { sums = await fetchText(sumUrl); }
|
|
183
|
+
catch (e) { fatal(`could not fetch checksums.txt: ${e.message}`); }
|
|
184
|
+
const line = sums.split("\n").find((l) => l.endsWith(` ${tarName}`));
|
|
185
|
+
if (!line) fatal(`checksums.txt has no entry for ${tarName}`);
|
|
186
|
+
const expected = line.split(/\s+/)[0];
|
|
187
|
+
const actual = await sha256OfFile(tarPath);
|
|
188
|
+
if (actual !== expected) {
|
|
189
|
+
fs.unlinkSync(tarPath);
|
|
190
|
+
fatal(`checksum mismatch for ${tarName}\n expected ${expected}\n got ${actual}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
await maybeVerifyCosign(dir, sums);
|
|
194
|
+
|
|
195
|
+
process.stderr.write(`dew: extracting\n`);
|
|
196
|
+
if (!extractTarGz(tarPath, dir, spec.binName)) {
|
|
197
|
+
fatal(`tarball missing ${spec.binName}`);
|
|
198
|
+
}
|
|
199
|
+
fs.unlinkSync(tarPath);
|
|
200
|
+
return binPath;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
(async () => {
|
|
204
|
+
const override = process.env.DEW_BINARY;
|
|
205
|
+
let bin;
|
|
206
|
+
if (override) {
|
|
207
|
+
if (!fs.existsSync(override)) fatal(`DEW_BINARY=${override} does not exist`);
|
|
208
|
+
bin = override;
|
|
209
|
+
} else {
|
|
210
|
+
bin = await ensureBinary();
|
|
211
|
+
}
|
|
212
|
+
const result = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
213
|
+
if (result.error) fatal(result.error.message);
|
|
214
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
215
|
+
})().catch((e) => fatal(e.message));
|
package/package.json
CHANGED
|
@@ -1,37 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dew",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.7.31",
|
|
4
|
+
"description": "Sandboxed Linux compute, agent-native and human-friendly.",
|
|
5
|
+
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/
|
|
9
|
-
},
|
|
10
|
-
"license": "MIT",
|
|
11
|
-
"bugs": {
|
|
12
|
-
"url": "https://github.com/wlabranche/dew/issues"
|
|
13
|
-
},
|
|
14
|
-
"scripts": {
|
|
15
|
-
"test": "echo yay"
|
|
8
|
+
"url": "git+https://github.com/solcreek/dew.git"
|
|
16
9
|
},
|
|
17
|
-
"homepage": "https://github.com/wlabranche/dew",
|
|
18
|
-
"main": "./lib/dew",
|
|
19
|
-
"keywords": [
|
|
20
|
-
"make",
|
|
21
|
-
"tests",
|
|
22
|
-
"magic"
|
|
23
|
-
],
|
|
24
10
|
"bin": {
|
|
25
|
-
"dew": "
|
|
26
|
-
"undew": "./bin/undew",
|
|
27
|
-
"detest": "./bin/detest"
|
|
11
|
+
"dew": "bin/dew"
|
|
28
12
|
},
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
13
|
+
"files": [
|
|
14
|
+
"bin/dew",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "node --test test/*.test.mjs"
|
|
33
19
|
},
|
|
34
20
|
"engines": {
|
|
35
|
-
"node": "
|
|
21
|
+
"node": ">=18"
|
|
36
22
|
}
|
|
37
23
|
}
|
package/.jshintrc
DELETED
package/.npmignore
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Logs
|
|
2
|
-
logs
|
|
3
|
-
*.log
|
|
4
|
-
|
|
5
|
-
# Runtime data
|
|
6
|
-
pids
|
|
7
|
-
*.pid
|
|
8
|
-
*.seed
|
|
9
|
-
|
|
10
|
-
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
11
|
-
lib-cov
|
|
12
|
-
|
|
13
|
-
# Coverage directory used by tools like istanbul
|
|
14
|
-
coverage
|
|
15
|
-
|
|
16
|
-
# gulp intermediate storage
|
|
17
|
-
.gulp
|
|
18
|
-
|
|
19
|
-
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
|
20
|
-
build/Release
|
|
21
|
-
|
|
22
|
-
# Dependency directory
|
|
23
|
-
# Deployed apps should consider commenting this line out:
|
|
24
|
-
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
|
|
25
|
-
node_modules
|
|
26
|
-
|
|
27
|
-
test
|
package/.travis.yml
DELETED
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2014 Will LaBranche
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/bin/detest
DELETED
package/bin/undew
DELETED
package/lib/detest.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var fs = require( 'fs' ),
|
|
4
|
-
path = require( 'path' );
|
|
5
|
-
|
|
6
|
-
var detest = function() {
|
|
7
|
-
var file, suffix, full;
|
|
8
|
-
|
|
9
|
-
if ( process.argv.length > 2 ) {
|
|
10
|
-
file = process.argv[2].split( '.' )[0];
|
|
11
|
-
suffix = process.argv[2].split( '.' )[1] || 'js';
|
|
12
|
-
full = file + '-file' + '.' + suffix;
|
|
13
|
-
if (fs.existsSync( file + '-test' + '.' + suffix ) ) {
|
|
14
|
-
fs.unlinkSync(file + '-test' + '.' + suffix);
|
|
15
|
-
console.log( 'the test shoudld be gone' );
|
|
16
|
-
} else {
|
|
17
|
-
console.log( 'there isn\'t a test for that...' );
|
|
18
|
-
}
|
|
19
|
-
} else {
|
|
20
|
-
// in the future this may want to ask about removing all tests from dir
|
|
21
|
-
console.log( 'you need to want to destroy something...' );
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
module.exports = detest;
|
package/lib/dew/buildFiles.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var fs = require( 'fs' );
|
|
4
|
-
|
|
5
|
-
var makeJS = require( './buildFile/makeJS' ),
|
|
6
|
-
makeCoffee = require( './buildFile/makeCoffee' ),
|
|
7
|
-
jsTest = require( './buildTest/jsTest' ),
|
|
8
|
-
coffeeTest = require( './buildTest/coffeeTest' );
|
|
9
|
-
|
|
10
|
-
var buildFiles = function ( fileData ) {
|
|
11
|
-
|
|
12
|
-
var filePath = fileData.path + '/' + fileData.fileName + '.' + fileData.ext,
|
|
13
|
-
testPath = fileData.path + '/' + fileData.fileName + '-test.' + fileData.ext,
|
|
14
|
-
mainFile = fs.existsSync( filePath ),
|
|
15
|
-
testFile = fs.existsSync( testPath ),
|
|
16
|
-
resultFile, resultTest;
|
|
17
|
-
|
|
18
|
-
if ( !mainFile ) {
|
|
19
|
-
if ( fileData.ext === 'coffee' ) {
|
|
20
|
-
resultFile = makeCoffee( fileData.file );
|
|
21
|
-
} else {
|
|
22
|
-
resultFile = makeJS( fileData.file );
|
|
23
|
-
}
|
|
24
|
-
fs.writeFileSync( filePath, resultFile );
|
|
25
|
-
console.log( 'wrote ' + fileData.fileName + '.' + fileData.ext );
|
|
26
|
-
}
|
|
27
|
-
if ( !testFile ) {
|
|
28
|
-
if ( fileData.ext === 'coffee' ) {
|
|
29
|
-
resultTest = coffeeTest( fileData.file );
|
|
30
|
-
} else {
|
|
31
|
-
resultTest = jsTest( fileData.file );
|
|
32
|
-
}
|
|
33
|
-
fs.writeFileSync( testPath, resultTest );
|
|
34
|
-
console.log( 'wrote ' + fileData.fileName + '-test.' + fileData.ext );
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
module.exports = buildFiles;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var coffeeTest = function ( name ) {
|
|
4
|
-
var file = name + ' = require \'./' + name + '.coffee\'\n' +
|
|
5
|
-
'\n' +
|
|
6
|
-
'mocha = require \'mocha\'\n' +
|
|
7
|
-
'expect = require \'chai\'\n' +
|
|
8
|
-
' .expect\n' +
|
|
9
|
-
'\n' +
|
|
10
|
-
'describe \'' + name + '\', ->\n' +
|
|
11
|
-
' it \'should exist\', ->\n' +
|
|
12
|
-
' expect( ' + name + ' ).to.exist\n';
|
|
13
|
-
|
|
14
|
-
return file;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
module.exports = coffeeTest;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var jsTest = function( name ){
|
|
4
|
-
var file = 'var ' + name + ' = require( \'./' + name + '.js\' );\n' +
|
|
5
|
-
'\n' +
|
|
6
|
-
'var mocha = require( \'mocha\' ),\n' +
|
|
7
|
-
' expect = require( \'chai\' ).expect;\n' +
|
|
8
|
-
'\n' +
|
|
9
|
-
'describe( \'' + name + '\', function() {\n' +
|
|
10
|
-
' it( \'should exist\', function() {\n' +
|
|
11
|
-
' return expect( ' + name + ' ).to.exist;\n' +
|
|
12
|
-
' });\n' +
|
|
13
|
-
'});\n';
|
|
14
|
-
|
|
15
|
-
return file;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
module.exports = jsTest;
|
package/lib/dew/index.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var fs = require( 'fs' );
|
|
4
|
-
|
|
5
|
-
var parseInput = require( './utility/parseInput' ),
|
|
6
|
-
buildFiles = require( './buildFiles' );
|
|
7
|
-
|
|
8
|
-
var dew = function ( fileList, path ) {
|
|
9
|
-
|
|
10
|
-
fileList.forEach( function ( file ) {
|
|
11
|
-
var fileInfo = parseInput( file, path ),
|
|
12
|
-
files;
|
|
13
|
-
if ( fileInfo.isDir ) {
|
|
14
|
-
files = fs.readdirSync( path + '/' + file );
|
|
15
|
-
dew( files, path + '/' + file );
|
|
16
|
-
} else {
|
|
17
|
-
// make files
|
|
18
|
-
buildFiles( fileInfo );
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
module.exports = dew;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var findup = require( 'findup-sync' );
|
|
4
|
-
|
|
5
|
-
var cwd = process.cwd(),
|
|
6
|
-
projectPackage = findup( 'package.json', { cwd: cwd } );
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var getExt = function ( targetName ) {
|
|
10
|
-
var ext, parts;
|
|
11
|
-
if ( projectPackage ) {
|
|
12
|
-
if ( projectPackage.config && projectPackage.config.dew ) {
|
|
13
|
-
ext = projectPackage.config.dew.ext;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
if ( !ext ) {
|
|
17
|
-
parts = targetName.split('.');
|
|
18
|
-
if ( parts.length > 1 ) {
|
|
19
|
-
ext = parts.pop();
|
|
20
|
-
} else {
|
|
21
|
-
ext = 'js';
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
if ( ext !== 'js' && ext !== 'coffee' ) {
|
|
25
|
-
throw new Error( 'this only works for js and coffee' );
|
|
26
|
-
}
|
|
27
|
-
return ext;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
module.exports = getExt;
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// add an isDir property?
|
|
4
|
-
var fs = require( 'fs' );
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var getExt = require( './getExt' );
|
|
8
|
-
|
|
9
|
-
var parseInput = function ( input, path ) {
|
|
10
|
-
var fullPath = path + '/' + input,
|
|
11
|
-
exists = fs.existsSync( fullPath ),
|
|
12
|
-
isDir = false,
|
|
13
|
-
isTest = false,
|
|
14
|
-
ext = null,
|
|
15
|
-
parts = {},
|
|
16
|
-
nameParts = input.split( '.' ),
|
|
17
|
-
tempTest;
|
|
18
|
-
|
|
19
|
-
if ( exists ) {
|
|
20
|
-
isDir = fs.lstatSync( fullPath ).isDirectory();
|
|
21
|
-
}
|
|
22
|
-
if ( !isDir ) {
|
|
23
|
-
ext = getExt( input );
|
|
24
|
-
}
|
|
25
|
-
if ( nameParts[ nameParts.length - 1 ] === ext ) {
|
|
26
|
-
nameParts.pop();
|
|
27
|
-
}
|
|
28
|
-
if ( input.indexOf( 'test' ) > -1 ) {
|
|
29
|
-
if ( nameParts.length > 1 ) {
|
|
30
|
-
// lazy way of handling dot notation
|
|
31
|
-
nameParts.pop();
|
|
32
|
-
} else if ( input.indexOf( '-' ) > -1 ) {
|
|
33
|
-
// lazy way of handling '-test'
|
|
34
|
-
tempTest = nameParts[ 0 ].split( '-' );
|
|
35
|
-
tempTest.pop();
|
|
36
|
-
nameParts[ 0 ] = tempTest.join( '-' );
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// remove 'test' from name, for tdd
|
|
41
|
-
parts.isDir = isDir;
|
|
42
|
-
parts.ext = ext;
|
|
43
|
-
parts.fileName = nameParts.join('.') || null;
|
|
44
|
-
parts.path = path;
|
|
45
|
-
|
|
46
|
-
return parts;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
module.exports = parseInput;
|
package/lib/undew.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var fs = require( 'fs' );
|
|
4
|
-
|
|
5
|
-
var undew = function() {
|
|
6
|
-
var file, suffix;
|
|
7
|
-
if ( process.argv.length > 2 ){
|
|
8
|
-
file = process.argv[2].split( '.' )[0];
|
|
9
|
-
suffix = process.argv[2].split( '.' )[1] || 'js';
|
|
10
|
-
if ( fs.existsSync(file + '.' + suffix )){
|
|
11
|
-
fs.unlinkSync( file + '.' + suffix );
|
|
12
|
-
if ( fs.existsSync( file + '-test' + '.' + suffix ) ){
|
|
13
|
-
fs.unlinkSync( file + '-test' + '.' + suffix );
|
|
14
|
-
}
|
|
15
|
-
console.log( 'they should be gone forever' );
|
|
16
|
-
}else{
|
|
17
|
-
console.log( 'that doesn\'t exist... so... DONE!' );
|
|
18
|
-
}
|
|
19
|
-
}else{
|
|
20
|
-
console.log( 'input something for me to banish, please' );
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
module.exports = undew;
|