diff --git a/.gitignore b/.gitignore index 415b7c79..988754a8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,11 +2,27 @@ .idea .DS_Store -build/ -src/bundles/js/ -src/js/core.js -src/js/std.js -src/version.h -node_modules/ -docs/api/ -test_dir*/ +/build/ +/src/bundles/js/ +/src/js/core.js +/src/js/std.js +/src/version.h +/node_modules/ +/docs/api/ +/test_dir*/ + +#External modules +/benchmark/extras/ +/deps/extras/ +/examples/extras/ +/tests/extras/ +/src/bundles/c/extras/ +/src/js/extras/ +/src/extras/ +/extras/ +/docs/types/extras/ + +/src/*.c.frag + +#Module files +modules.json \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b96e00e..38a8a18e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,13 @@ cmake_minimum_required(VERSION 3.14) project(tjs LANGUAGES C) +if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/deps/extras") + enable_language(CXX) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS ON) + set(CMAKE_CXX_STANDARD 20) +endif() + include(ExternalProject) include(GNUInstallDirs) @@ -16,6 +23,8 @@ set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) set(CMAKE_C_STANDARD 11) + + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) list(APPEND tjs_cflags -Wall -g) @@ -57,6 +66,10 @@ add_subdirectory(deps/sqlite3 EXCLUDE_FROM_ALL) set(BUILD_WASI "simple" CACHE STRING "WASI implementation") add_subdirectory(deps/wasm3 EXCLUDE_FROM_ALL) +if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/deps/extras") + add_subdirectory(deps/extras EXCLUDE_FROM_ALL) +endif() + if(BUILD_WITH_MIMALLOC) option(MI_OVERRIDE "" OFF) option(MI_BUILD_SHARED "" OFF) @@ -68,6 +81,9 @@ endif() find_package(CURL REQUIRED) +file(GLOB_RECURSE src_extras "src/extras/**/*.c" "src/extras/**/*.cpp") +file(GLOB src_bundles_extras "src/bundles/c/extras/*.c") + add_library(tjs STATIC src/builtins.c src/curl-utils.c @@ -100,6 +116,8 @@ add_library(tjs STATIC src/bundles/c/core/polyfills.c src/bundles/c/core/run-main.c src/bundles/c/core/worker-bootstrap.c + ${src_extras} + ${src_bundles_extras} deps/quickjs/cutils.c ) @@ -152,7 +170,8 @@ target_compile_options(tjs PRIVATE ${tjs_cflags}) target_compile_definitions(tjs PRIVATE TJS__PLATFORM="${TJS_PLATFORM}") target_include_directories(tjs PRIVATE ${CURL_INCLUDE_DIRS}) target_include_directories(tjs PUBLIC src) -target_link_libraries(tjs qjs uv_a m3 sqlite3 m pthread ${CURL_LIBRARIES}) +target_include_directories(tjs PRIVATE deps) +target_link_libraries(tjs qjs uv_a m3 sqlite3 m pthread ${CURL_LIBRARIES} ${EXTRA_MODULES}) if (BUILD_WITH_MIMALLOC) target_compile_definitions(tjs PRIVATE TJS__HAS_MIMALLOC) @@ -170,4 +189,4 @@ set_target_properties(tjs-cli add_executable(tjsc EXCLUDE_FROM_ALL src/qjsc.c ) -target_link_libraries(tjsc qjs m) +target_link_libraries(tjsc qjs m) \ No newline at end of file diff --git a/Makefile b/Makefile index 6679ed6f..e5ed08f7 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ JS_NO_STRIP?=0 TJS=$(BUILD_DIR)/tjs QJSC=$(BUILD_DIR)/tjsc STDLIB_MODULES=$(wildcard src/js/stdlib/*.js) +EXTRAS_MODULES=$(wildcard src/js/extras/*.js) ESBUILD?=npx esbuild ESBUILD_PARAMS_COMMON=--target=es2022 --platform=neutral --format=esm --main-fields=main,module ESBUILD_PARAMS_MINIFY=--minify @@ -109,18 +110,29 @@ src/bundles/js/stdlib/%.js: src/js/stdlib/*.js src/js/stdlib/ffi/*.js $(ESBUILD_PARAMS_MINIFY) \ $(ESBUILD_PARAMS_COMMON) -src/bundles/c/stdlib/%.c: $(QJSC) src/bundles/js/stdlib/%.js +src/bundles/c/extras/%.c: $(QJSC) src/bundles/js/extras/%.js @mkdir -p $(basename $(dir $@)) $(QJSC) -m \ $(QJSC_PARAMS_STIP) \ -o $@ \ -n "tjs:$(basename $(notdir $@))" \ -p tjs__ \ - src/bundles/js/stdlib/$(basename $(notdir $@)).js + src/bundles/js/extras/$(basename $(notdir $@)).js + +src/bundles/js/extras/%.js: src/js/extras/*.js + $(ESBUILD) src/js/extras/$(notdir $@) \ + --bundle \ + --outfile=$@ \ + --external:buffer \ + --external:crypto \ + --external:"tjs:*" \ + $(ESBUILD_PARAMS_MINIFY) \ + $(ESBUILD_PARAMS_COMMON) stdlib: $(addprefix src/bundles/c/stdlib/, $(patsubst %.js, %.c, $(notdir $(STDLIB_MODULES)))) +extras: $(addprefix src/bundles/c/extras/, $(patsubst %.js, %.c, $(notdir $(EXTRAS_MODULES)))) -js: core stdlib +js: core stdlib extras install: $(TJS) cmake --build $(BUILD_DIR) --target install @@ -140,10 +152,11 @@ format: test: ./$(BUILD_DIR)/tjs test tests/ + if [ -d "tests/extras" ]; then ./$(BUILD_DIR)/tjs test tests/extras/; fi test-advanced: cd tests/advanced && npm install ./$(BUILD_DIR)/tjs test tests/advanced/ -.PRECIOUS: src/bundles/js/core/%.js src/bundles/js/stdlib/%.js -.PHONY: all js debug install clean distclean format test test-advanced core stdlib $(TJS) +.PRECIOUS: src/bundles/js/core/%.js src/bundles/js/stdlib/%.js src/bundles/js/extras/%.js +.PHONY: all js debug install clean distclean format test test-advanced core stdlib extras $(TJS) \ No newline at end of file diff --git a/deps/quickjs b/deps/quickjs index 99c6719b..accd2d57 160000 --- a/deps/quickjs +++ b/deps/quickjs @@ -1 +1 @@ -Subproject commit 99c6719b7d2fe5aba4e9ff28936173fd0c4f2805 +Subproject commit accd2d5758694cdc4f0e1a2f5f21e4b5405d4e56 diff --git a/docs/tsconfig.doc.json b/docs/tsconfig.doc.json index ca3cd296..d04634fc 100644 --- a/docs/tsconfig.doc.json +++ b/docs/tsconfig.doc.json @@ -1,18 +1,22 @@ { - "compilerOptions": { - "lib": ["ES2020", "dom"], - "noImplicitAny": true - }, - "typedocOptions": { - "name": "txiki.js", - "entryPoints": [ "types/" ], - "entryPointStrategy": "expand", - "out": "api/", - "readme": "intro.md", - "disableSources": true, - "exclude":["types/index.d.ts"] - }, - "watchOptions": { - "excludeDirectories": ["api/*"] - } + "compilerOptions": { + "lib": ["ES2020", "dom"], + "target": "ESNext", + "noImplicitAny": true, + "baseUrl": ".", + "typeRoots": ["./node_modules/@types"] + }, + "typedocOptions": { + "name": "txiki.js", + "entryPoints": ["types/"], + "entryPointStrategy": "expand", + "out": "api/", + "readme": "intro.md", + "disableSources": true, + "exclude": ["types/index.d.ts"] + }, + "watchOptions": { + "excludeDirectories": ["api/*"] + }, + "include": ["types/**/*.ts"] } diff --git a/docs/types/index.d.ts b/docs/types/index.d.ts index 0f0811cc..5bfcf107 100644 --- a/docs/types/index.d.ts +++ b/docs/types/index.d.ts @@ -1,11 +1,12 @@ -/// -/// -/// -/// -/// -/// -/// -/// -/// +import "./txikijs.d.ts" +import "./assert.d.ts" +import "./ffi.d.ts" +import "./getopts.d.ts" +import "./hashing.d.ts" +import "./ipaddr.d.ts" +import "./path.d.ts" +import "./sqlite.d.ts" +import "./uuid.d.ts" +import "./extras/index.d.ts" export {}; diff --git a/extras-helper.mjs b/extras-helper.mjs new file mode 100755 index 00000000..69a73537 --- /dev/null +++ b/extras-helper.mjs @@ -0,0 +1,285 @@ +#!/bin/env node +/** +The MIT License (MIT) + +Copyright (c) 2024-present karurochari + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +let STRICT = false; +const protocol_version = [2, 2, 0] +//TODO: take this from the makefile? There must be a better way to handle this. +const runtime_version = [23, 12, 0] + +import { readFile, writeFile, mkdir, rm, cp } from 'node:fs/promises' +import { existsSync } from 'node:fs'; + +import { dirname } from 'node:path' +import util from 'node:util'; + +import { program } from 'commander'; +import { exec as _exec } from 'node:child_process'; +const exec = util.promisify(_exec); + +import { Readable } from 'node:stream' +import fg from 'fast-glob' + +/** + * It checks the version of the runtime & module interface against the one presented by a module + * @param {string} name + * @param {[number,number,number]|undefined} modprotocol_version + * @param {[number,number,number]|undefined} runtime_version + * @param {boolean} strict + * @returns {boolean} True if versions are matching + */ +function check_versions(strict, name, modprotocol_version, runtime_version) { + if (strict === true) { + if (modprotocol_version === undefined) { + console.error( + `Module is not versioned against the module protocol.`, + ); + return false; + } + if (runtime_version === undefined) { + console.error( + `Module is not versioned against the runtime.`, + ); + return false; + } + } + else { + if (modprotocol_version === undefined) + console.warn( + `Module has no protocol version reported. It might end up being incompatible`, + ); + if (runtime_version === undefined) + console.warn( + `Module has no runtime version reported. It might end up being incompatible`, + ); + } + + //TODO: Add any logic to be determined to ensure compatibility here. + return true; +} + +/** + * Recover a native dependency from a git server. + * @param {string} name Name of the submodule + * @param {string} url Source + * @param {string} branch Branch/Tag + */ +async function clone_shallow(name, url, branch) { + await rm(`./deps/extras/${name}`, { recursive: true, force: true }) + await exec(`git clone --recurse-submodules --shallow-submodules --depth 1 --single-branch --branch ${branch} ${url} ./deps/extras/${name}`); +} + +async function copy_template(path, subdir) { + const files = await fg(`./extras/${path}/${subdir}/*.js`); + const prefix = `./${subdir}/${path}/${subdir}/`.length + const suffix = ".js".length + for (const file of files) { + const name = file.substring(prefix, file.length - suffix).replaceAll("[module]", path) + await writeFile(`./${subdir}/extras/${name}.js`, ((await readFile(file)).toString().replaceAll('__MODULE__', path))) + } +} + + +async function retrieve(name, path, prefix) { + //From the internet + if (path.startsWith('https://') || path.startsWith('http://')) { + await writeFile( + `${prefix}${name}.tar.gz`, + Readable.fromWeb( + (await fetch(path)).body, + ), + ) + await exec(`mkdir ${prefix}${name} && tar -xvzf ${prefix}${name}.tar.gz -C ${prefix}${name} --strip-components=1`); + await rm(`${prefix}${name}.tar.gz`) + } + //Local folder + else { + await cp(path, `${prefix}${name}`, { recursive: true, dereference: true, errorOnExist: false }) + } +} + +async function install(path) { + let modcfg = {} + if (await existsSync(`./extras/${path}/module.json`)) modcfg = JSON.parse((await readFile(`./extras/${path}/module.json`)).toString()) + if (!check_versions(STRICT, path, modcfg["module-version"], modcfg["runtime-version"])) { + console.error(`Unable to properly handle module ${path}`) + process.exit(1) + } + + const cmake = [] + const names = [] + + for (const [name, info] of Object.entries(modcfg["native-deps"] ?? {})) { + if (info.url) { + console.log( + `Fetch of ${name} @ ${info.url}`, + ); + await retrieve(name, info.url, './deps/extras/') + } + else { + console.log( + `Shallow cloning ${name} @ ${info.repo} branch ${info.branch}`, + ); + await clone_shallow(name, info.repo, info.branch); + } + cmake.push("block()") + + //Build the extras cmake entries + for (const item of Object.entries(info.env ?? {})) { + //TODO: Evaluate if we want to have escaping, or a better handling of types. + //In general all this part is likely to be reworked and extended at some point. + const { value, type, force } = item[1] + cmake.push(`set(${item[0]} ${value} CACHE ${type} "Handle ${name} ${item[0]} variable" ${force ? 'FORCE' : ''})`) + } + if (info['raw-cmake']) cmake.push(info['raw-cmake']) + cmake.push(`add_subdirectory(./${name} EXCLUDE_FROM_ALL)`) + cmake.push("endblock()") + names.push(...(info.symbols ?? [name])) + } + + await mkdir(`src/extras/${path}`, { errorOnExist: false }); + + //Copy over all files in src + { + const files = await fg(`./extras/${path}/src/**/*`); + const prefix = `./extras/${path}/src/`.length + for (const file of files) { + const name = file.substring(prefix).replaceAll("[module]", path) + const fullPath = `./src/extras/${path}/${name}` + await mkdir(dirname(fullPath), { errorOnExist: false, recursive: true }); + await writeFile(fullPath, ((await readFile(file)).toString().replaceAll('__MODULE__', path))) + + } + } + + //While js/ts files must be already reduced in a bundle by this point. + await writeFile(`./src/js/extras/${path}.js`, ((await readFile(`./extras/${path}/bundle/[module].js`)).toString().replaceAll('__MODULE__', path))) + await writeFile(`./docs/types/extras/${path}.d.ts`, ((await readFile(`./extras/${path}/bundle/[module].d.ts`)).toString().replaceAll('__MODULE__', path))) + await copy_template(path, 'examples') + await copy_template(path, 'benchmarks') + await copy_template(path, 'tests') + + + return { cmake: cmake, names: names } +} + +async function clear() { + await rm('extras/', { recursive: true, force: true }); + await rm('src/extras/', { recursive: true, force: true }); + await rm('src/js/extras/', { recursive: true, force: true }); + await rm('tests/extras/', { recursive: true, force: true }); + await rm('examples/extras/', { recursive: true, force: true }); + await rm('deps/extras/', { recursive: true, force: true }); + await rm('benchmark/extras/', { recursive: true, force: true }); + await rm('docs/types/extras/', { recursive: true, force: true }); + + await rm('./src/extras-bootstrap.c.frag', { force: true }) + await rm('./src/extras-headers.c.frag', { force: true }) + await rm('./src/extras-bundles.c.frag', { force: true }) + await rm('./src/extras-entries.c.frag', { force: true }) +} + +program + .name('extras-helper.mjs') + .description('A CLI to customize your txiki distribution') + +program.command('clear') + .description('Clear after your previous configuration') + .action(async () => { + await clear() + }) + +program.command('refresh') + .description('Refresh a single module, keeping the rest the same') + .argument("", 'module name ') + .argument("[filename]", 'filename for the configuration', './modules.json') + .option("-s, --strict", "Force checks for versions") + .action(async (modname, filename, options) => { + STRICT = options.strict + let config = undefined + try { + config = JSON.parse(await readFile(filename)) + } + catch (e) { + console.error("Unable to parse the config file.") + process.exit(1) + } + + await retrieve(modname, config[modname], './extras/') + await install(modname) + }) + +program.command('clone') + .description('Clear after your previous configuration') + .argument("[filename]", 'filename for the configuration', './modules.json') + .option("-s, --strict", "Force checks for versions") + .action(async (filename, options) => { + STRICT = options.strict + //For now, since I am too lazy to handle merging + await clear() + + await mkdir("extras/", { errorOnExist: false }); + await mkdir('src/extras/', { errorOnExist: false }); + await mkdir('src/js/extras/', { errorOnExist: false }); + await mkdir('tests/extras/', { errorOnExist: false }); + await mkdir('examples/extras/', { errorOnExist: false }); + await mkdir('deps/extras/', { errorOnExist: false }); + await mkdir('benchmark/extras/', { errorOnExist: false }); + await mkdir('docs/types/extras/', { errorOnExist: false }); + + let config = undefined + try { + config = JSON.parse(await readFile(filename)) + } + catch (e) { + console.error("Unable to parse the config file.") + process.exit(1) + } + + const cmake = [] + const names = [] + + for (const module of Object.entries(config)) { + await retrieve(module[0], module[1], './extras/') + const moduleInfo = (await install(module[0])) + cmake.push(moduleInfo.cmake.join('\n')) + names.push(...moduleInfo.names) + } + + //Placeholder for now + await writeFile('deps/extras/CMakeLists.txt', `${cmake.join("\n")}\nset(EXTRA_MODULES "${names.join(' ')}" CACHE STRING "" FORCE)`) + await writeFile('./modules.json', JSON.stringify(config, null, 4)) + + //Construct src/extras.bootstrap to initialize the extra modules + await writeFile('./src/extras-bootstrap.c.frag', Object.keys(config).map(x => `tjs__mod_${x}_init(ctx, ns);`).join('\n')) + await writeFile('./src/extras-headers.c.frag', Object.keys(config).map(x => `#include "./extras/${x}/module.h"`).join('\n')) + await writeFile('./src/extras-bundles.c.frag', Object.keys(config).map(x => `#include "bundles/c/extras/${x}.c"`).join('\n')) + await writeFile('./src/extras-entries.c.frag', Object.keys(config).map(x => `{ "tjs:${x}", tjs__${x}, tjs__${x}_size},`).join('\n')) + + //Construct the ts header + await writeFile('./docs/types/extras/index.d.ts', Object.keys(config).map(x => `import "./${x}.d.ts";`).join('\n')) + }) + + +program.parse(); diff --git a/package-lock.json b/package-lock.json index 2cf273ba..e308edf5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,8 @@ "whatwg-url": "^14.0.0" }, "devDependencies": { + "commander": "^12.0.0", + "fast-glob": "^3.3.2", "typedoc": "^0.25.2" } }, @@ -686,9 +688,13 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", + "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", + "dev": true, + "engines": { + "node": ">=18" + } }, "node_modules/commondir": { "version": "1.0.1", @@ -1363,9 +1369,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -1626,6 +1632,11 @@ "node": ">=10" } }, + "node_modules/gh-pages/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "node_modules/gh-pages/node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -3465,9 +3476,10 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", + "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", + "dev": true }, "commondir": { "version": "1.0.1", @@ -3964,9 +3976,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -4164,6 +4176,11 @@ "globby": "^6.1.0" }, "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", diff --git a/package.json b/package.json index 81afc966..74ef12f2 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "api-docs": "typedoc --tsconfig docs/tsconfig.doc.json", "api-docs-watch": "typedoc --tsconfig docs/tsconfig.doc.json --watch --preserveWatchOutput --logLevel Verbose", "deploy-api-docs": "gh-pages -d docs/api -e api -u \"github-actions-bot \"", + "extra-modules-clear": "./extras-helper.mjs clear", + "extra-modules-clone": "./extras-helper.mjs clone", "lint": "eslint --max-warnings 0 ." }, "license": "MIT", @@ -35,6 +37,8 @@ "whatwg-url": "^14.0.0" }, "devDependencies": { + "commander": "^12.0.0", + "fast-glob": "^3.3.2", "typedoc": "^0.25.2" } } diff --git a/src/builtins.c b/src/builtins.c index f55bfd92..f878a69c 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -30,6 +30,11 @@ #include "bundles/c/stdlib/path.c" #include "bundles/c/stdlib/sqlite.c" #include "bundles/c/stdlib/uuid.c" + +#if __has_include("extras-bundles.c.frag") +#include "extras-bundles.c.frag" +#endif + #include "private.h" @@ -48,6 +53,9 @@ static tjs_builtin_t builtins[] = { { "tjs:path", tjs__path, tjs__path_size }, { "tjs:sqlite", tjs__sqlite, tjs__sqlite_size }, { "tjs:uuid", tjs__uuid, tjs__uuid_size }, + #if __has_include("extras-entries.c.frag") + #include "extras-entries.c.frag" + #endif { NULL, NULL, 0 }, }; diff --git a/src/private.h b/src/private.h index 49973ad1..24981a4d 100644 --- a/src/private.h +++ b/src/private.h @@ -78,6 +78,9 @@ void tjs__mod_wasm_init(JSContext *ctx, JSValue ns); void tjs__mod_worker_init(JSContext *ctx, JSValue ns); void tjs__mod_ws_init(JSContext *ctx, JSValue ns); void tjs__mod_xhr_init(JSContext *ctx, JSValue ns); +#if __has_include("extras-headers.c.frag") +#include "extras-headers.c.frag" +#endif #ifndef _WIN32 void tjs__mod_posix_socket_init(JSContext *ctx, JSValue ns); diff --git a/src/vm.c b/src/vm.c index bd86dbd3..b90c3ab9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -126,6 +126,9 @@ static void tjs__bootstrap_core(JSContext *ctx, JSValue ns) { #ifndef _WIN32 tjs__mod_posix_socket_init(ctx, ns); #endif + #if __has_include("extras-bootstrap.c.frag") + #include "extras-bootstrap.c.frag" + #endif } JSValue tjs__get_args(JSContext *ctx) {