1
1
'use strict';
2
2
3
+ var EventEmitter = require('events');
4
+ var fs = require('fs');
5
+ var util = require('util');
3
6
var http = require('http');
4
7
var crypto = require('crypto');
5
- var fs = require('fs');
6
8
var path = require('path');
7
9
var https = require('https');
8
10
var url = require('url');
9
11
10
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
-
12
- function _interopNamespace(e) {
13
- if (e && e.__esModule) return e;
14
- var n = Object.create(null);
15
- if (e) {
16
- Object.keys(e).forEach(function (k) {
17
- if (k !== 'default') {
18
- var d = Object.getOwnPropertyDescriptor(e, k);
19
- Object.defineProperty(n, k, d.get ? d : {
20
- enumerable: true,
21
- get: function () {
22
- return e[k];
23
- }
24
- });
25
- }
26
- });
27
- }
28
- n['default'] = e;
29
- return Object.freeze(n);
12
+ const readdir = util.promisify(fs.readdir);
13
+ const stat = util.promisify(fs.stat);
14
+ class CheapWatch extends EventEmitter {
15
+ constructor(data) {
16
+ super();
17
+ this.watch = true;
18
+ this.debounce = 10;
19
+ this.paths = new Map();
20
+ this._watchers = new Map();
21
+ this._timeouts = new Map();
22
+ this._queue = [];
23
+ this._status = 0;
24
+ Object.assign(this, data);
25
+ if (typeof this.dir !== 'string') {
26
+ throw new TypeError('dir must be a string');
27
+ }
28
+ if (this.filter && typeof this.filter !== 'function') {
29
+ throw new TypeError('filter must be a function');
30
+ }
31
+ if (typeof this.watch !== 'boolean') {
32
+ throw new TypeError('watch must be a boolean');
33
+ }
34
+ if (typeof this.debounce !== 'number') {
35
+ throw new TypeError('debounce must be a number');
36
+ }
37
+ }
38
+ async init() {
39
+ if (this._status !== 0) {
40
+ throw new Error('cannot call init() twice');
41
+ }
42
+ this._status = 1;
43
+ await this._recurse(this.dir);
44
+ this._status = 2;
45
+ }
46
+ close() {
47
+ if (this._status === 0 || this._status === 1) {
48
+ throw new Error('cannot call close() before init() finishes');
49
+ }
50
+ if (this._status === 4) {
51
+ throw new Error('cannot call close() twice');
52
+ }
53
+ this._status = 4;
54
+ for (const watcher of this._watchers.values()) {
55
+ watcher.close();
56
+ }
57
+ }
58
+ async _recurse(full) {
59
+ const path = full.slice(this.dir.length + 1);
60
+ const stats = await stat(full);
61
+ if (path) {
62
+ if (this.filter && !(await this.filter({ path, stats }))) {
63
+ return;
64
+ }
65
+ this.paths.set(path, stats);
66
+ }
67
+ if (stats.isDirectory()) {
68
+ if (this.watch) {
69
+ this._watchers.set(path, fs.watch(full, this._handle.bind(this, full)).on('error', () => { }));
70
+ }
71
+ await Promise.all((await readdir(full)).map(sub => this._recurse(full + '/' + sub)));
72
+ }
73
+ }
74
+ _handle(dir, event, file) {
75
+ this._debounce(dir);
76
+ this._debounce(dir + '/' + file);
77
+ }
78
+ _debounce(path) {
79
+ if (this._timeouts.has(path)) {
80
+ clearTimeout(this._timeouts.get(path));
81
+ }
82
+ this._timeouts.set(path, setTimeout(() => {
83
+ this._timeouts.delete(path);
84
+ this._enqueue(path);
85
+ }, this.debounce));
86
+ }
87
+ async _enqueue(full) {
88
+ this._queue.push(full);
89
+ if (this._status !== 2) {
90
+ return;
91
+ }
92
+ this._status = 3;
93
+ while (this._queue.length) {
94
+ const full = this._queue.shift();
95
+ const path = full.slice(this.dir.length + 1);
96
+ const stats = await stat(full).catch(() => { });
97
+ if (stats) {
98
+ if (this.filter && !(await this.filter({ path, stats }))) {
99
+ continue;
100
+ }
101
+ const isNew = !this.paths.has(path);
102
+ this.paths.set(path, stats);
103
+ if (path) {
104
+ this.emit('+', { path, stats, isNew });
105
+ }
106
+ if (stats.isDirectory() && !this._watchers.has(path)) {
107
+ await this._recurse(full);
108
+ for (const [new_path, stats] of this.paths.entries()) {
109
+ if (new_path.startsWith(path + '/')) {
110
+ this.emit('+', { path: new_path, stats, isNew: true });
111
+ }
112
+ }
113
+ }
114
+ }
115
+ else if (this.paths.has(path)) {
116
+ const stats = this.paths.get(path);
117
+ this.paths.delete(path);
118
+ this.emit('-', { path, stats });
119
+ if (this._watchers.has(path)) {
120
+ for (const old_path of this._watchers.keys()) {
121
+ if (old_path === path || old_path.startsWith(path + '/')) {
122
+ this._watchers.get(old_path).close();
123
+ this._watchers.delete(old_path);
124
+ }
125
+ }
126
+ for (const old_path of this.paths.keys()) {
127
+ if (old_path.startsWith(path + '/')) {
128
+ const stats = this.paths.get(old_path);
129
+ this.paths.delete(old_path);
130
+ this.emit('-', { path: old_path, stats });
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ this._status = 2;
137
+ }
30
138
}
31
139
32
- var http__default = /*#__PURE__*/_interopDefaultLegacy(http);
33
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
34
- var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
35
-
36
140
function parse$6 (str, loose) {
37
141
if (str instanceof RegExp) return { keys:false, pattern:str };
38
142
var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
@@ -171,7 +275,7 @@ function parser (req, toDecode) {
171
275
function onError(err, req, res) {
172
276
let code = (res.statusCode = err.code || err.status || 500);
173
277
if (typeof err === 'string' || Buffer.isBuffer(err)) res.end(err);
174
- else res.end(err.message || http__default['default'] .STATUS_CODES[code]);
278
+ else res.end(err.message || http .STATUS_CODES[code]);
175
279
}
176
280
177
281
const mount = fn => fn instanceof Polka ? fn.attach : fn;
@@ -221,7 +325,7 @@ class Polka extends Trouter {
221
325
}
222
326
223
327
listen() {
224
- (this.server = this.server || http__default['default'] .createServer()).on('request', this.attach);
328
+ (this.server = this.server || http .createServer()).on('request', this.attach);
225
329
this.server.listen.apply(this.server, arguments);
226
330
return this;
227
331
}
@@ -314,7 +418,7 @@ async function rc_read_file(file_path) {
314
418
file_or_dir.content = await Promise.all(
315
419
(await fs.promises.readdir(file_path))
316
420
.filter((name) => !name.endsWith("DS_Store") && name !== "node_modules")
317
- .map((name) => rc_read_file(path__namespace .join(file_path, name)))
421
+ .map((name) => rc_read_file(path .join(file_path, name)))
318
422
);
319
423
}
320
424
@@ -2172,7 +2276,7 @@ function parseOrigin(origin) {
2172
2276
return result
2173
2277
}
2174
2278
2175
- var minpath = path__default['default'] ;
2279
+ var minpath = path ;
2176
2280
2177
2281
var minproc = process;
2178
2282
@@ -24429,11 +24533,6 @@ async function format({
24429
24533
(title && make_slug$1(title, seen_slugs)) ||
24430
24534
false;
24431
24535
24432
- if (is_readme) {
24433
- console.log("BASE_DIR: ", dir);
24434
- console.log("FULL_DIR: ", `${dir}/${section_slug}`);
24435
- }
24436
-
24437
24536
const vfile$1 = vfile({
24438
24537
contents: markdown,
24439
24538
data: {
@@ -24868,6 +24967,8 @@ send.bind(null, 'PATCH');
24868
24967
send.bind(null, 'DELETE');
24869
24968
send.bind(null, 'PUT');
24870
24969
24970
+ const cache = {};
24971
+
24871
24972
async function cli() {
24872
24973
const {
24873
24974
pkg = "packages",
@@ -24879,42 +24980,38 @@ async function cli() {
24879
24980
return acc;
24880
24981
}, {});
24881
24982
24882
- // new CheapWatch({ dir, filter, watch = true, debounce = 10 });
24883
-
24884
- console.log(pkg, docs, project);
24885
-
24886
- let _docs;
24887
-
24888
- try {
24889
- _docs = await get_docs(project, pkg, docs);
24890
- } catch (e) {
24891
- console.log(e);
24892
- throw new Error("no docs");
24893
- }
24894
-
24895
- const transformed_docs = await Promise.all(
24896
- _docs.map(([project, docs]) =>
24897
- // @ts-ignore
24898
- transform(docs, project)
24899
- )
24983
+ let ready_for_cf;
24984
+ await process_docs(
24985
+ project,
24986
+ pkg,
24987
+ docs,
24988
+ (data) => (ready_for_cf = data)
24900
24989
);
24901
24990
24902
- const ready_for_cf = transformed_docs
24903
- .map((d) =>
24904
- d.map(({ content, project, type }) =>
24905
- //@ts-ignore
24906
- transform_cloudflare(content, { project, type, keyby: "slug" })
24907
- )
24908
- )
24909
- .flat(2);
24910
-
24911
- console.log(JSON.stringify(ready_for_cf, null, 2));
24991
+ const pkg_watch = new CheapWatch({
24992
+ dir: path.join(process.cwd(), pkg),
24993
+ debounce: 40,
24994
+ });
24995
+ const doc_watch = new CheapWatch({
24996
+ dir: path.join(process.cwd(), docs),
24997
+ debounce: 40,
24998
+ });
24912
24999
24913
- const is_valid = ready_for_cf.every(
24914
- ({ value, key }) => typeof value === "string" && typeof key === "string"
24915
- );
25000
+ await pkg_watch.init();
25001
+ await doc_watch.init();
25002
+ let cons = 0;
25003
+ pkg_watch.on("+", ({ path, stats, isNew }) => {
25004
+ if (!/.*\.\w+/.test(path)) return;
24916
25005
24917
- console.log(is_valid ? "\nEVERYTHING IS VALID\n" : "\nTHIS IS NOT VALID\n");
25006
+ process_docs(project, pkg, docs, (data) => (ready_for_cf = data));
25007
+ });
25008
+ doc_watch.on("+", ({ path, stats, isNew }) => {
25009
+ if (!/.*\.\w+/.test(path)) return;
25010
+ console.log("docs", path);
25011
+ console.time(`docs${cons}`);
25012
+ process_docs(project, pkg, docs, (data) => (ready_for_cf = data));
25013
+ console.timeEnd(`docs${cons++}`);
25014
+ });
24918
25015
24919
25016
24920
25017
@@ -24945,9 +25042,8 @@ async function cli() {
24945
25042
console.log(req.originalUrl);
24946
25043
24947
25044
if (!match)
24948
- match = await (
24949
- await get(`https://api.svelte.dev/${req.originalUrl}`)
24950
- ).data;
25045
+ match =
25046
+ cache[req.originalUrl] || (await fetch_and_cache(req.originalUrl));
24951
25047
24952
25048
if (match)
24953
25049
send$1(res, 200, typeof match === "string" ? match : match.value);
@@ -24967,13 +25063,12 @@ async function cli() {
24967
25063
({ key }) => key === _key
24968
25064
);
24969
25065
25066
+ //TODO: cache this lcoally
24970
25067
if (!match)
24971
- match = await (
24972
- await get(`https://api.svelte.dev/${req.originalUrl}`)
24973
- ).data;
25068
+ match =
25069
+ cache[req.originalUrl] || (await fetch_and_cache(req.originalUrl));
24974
25070
24975
- if (match)
24976
- send$1(res, 200, typeof match === "string" ? match : match.value);
25071
+ if (match) send$1(res, 200, match.value);
24977
25072
else
24978
25073
send$1(res, 404, {
24979
25074
message: `'${project}@${version}' '${type}' entry for '${slug}' not found.`,
@@ -24985,4 +25080,51 @@ async function cli() {
24985
25080
});
24986
25081
}
24987
25082
25083
+ async function fetch_and_cache(url) {
25084
+ try {
25085
+ const res = await (await get(`https://api.svelte.dev/${url}`)).data;
25086
+
25087
+ cache[url] = { key: url, value: res };
25088
+ return { key: url, value: res };
25089
+ } catch (e2) {
25090
+ return false;
25091
+ }
25092
+ }
25093
+ let count = 0;
25094
+ async function process_docs(
25095
+ project,
25096
+ pkg,
25097
+ docs,
25098
+ cb
25099
+ ) {
25100
+ let _docs;
25101
+
25102
+ try {
25103
+ _docs = await get_docs(project, pkg, docs);
25104
+ } catch (e) {
25105
+ console.log(e);
25106
+ throw new Error("no docs");
25107
+ }
25108
+
25109
+ const transformed_docs = await Promise.all(
25110
+ _docs.map(([project, docs]) =>
25111
+ // @ts-ignore
25112
+ transform(docs, project)
25113
+ )
25114
+ );
25115
+
25116
+ const ready_for_cf = transformed_docs
25117
+ .map((d) =>
25118
+ d.map(({ content, project, type }) =>
25119
+ //@ts-ignore
25120
+ transform_cloudflare(content, { project, type, keyby: "slug" })
25121
+ )
25122
+ )
25123
+ .flat(2);
25124
+
25125
+ cb(ready_for_cf);
25126
+ count += 1;
25127
+ console.log(count);
25128
+ }
25129
+
24988
25130
module.exports = cli;
0 commit comments