{"id":17359117,"url":"https://github.com/nathanjhood/noderc","last_synced_at":"2026-05-06T02:39:51.463Z","repository":{"id":216400036,"uuid":"741233773","full_name":"nathanjhood/noderc","owner":"nathanjhood","description":"CMakeRC as a NodeJs C++ Addon.","archived":false,"fork":false,"pushed_at":"2024-02-09T02:15:46.000Z","size":195,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-01T19:21:52.527Z","etag":null,"topics":["binary","cmake","cmake-js","cmake-rc","cpp","javascript","node-addon-api","node-js","nodejs","typescript"],"latest_commit_sha":null,"homepage":"","language":"CMake","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nathanjhood.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-10T01:07:37.000Z","updated_at":"2024-10-07T19:19:00.000Z","dependencies_parsed_at":"2024-12-06T10:23:31.006Z","dependency_job_id":"6106c5d7-47e2-4f2a-8dc8-d5bd11e5ec57","html_url":"https://github.com/nathanjhood/noderc","commit_stats":null,"previous_names":["nathanjhood/noderc"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanjhood%2Fnoderc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanjhood%2Fnoderc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanjhood%2Fnoderc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanjhood%2Fnoderc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nathanjhood","download_url":"https://codeload.github.com/nathanjhood/noderc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245870347,"owners_count":20686011,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["binary","cmake","cmake-js","cmake-rc","cpp","javascript","node-addon-api","node-js","nodejs","typescript"],"created_at":"2024-10-15T19:08:13.463Z","updated_at":"2026-05-06T02:39:51.417Z","avatar_url":"https://github.com/nathanjhood.png","language":"CMake","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NodeRC\n\nCMakeRC as a NodeJs C++ Addon.\n\nServe a binary-compiled embedded filesystem as a Javascript object in NodeJS.\n\n```.js\nimport noderc from '@nathanjhood/noderc';\n\nconst fs = noderc.getFileSystemObject();\nconst favicon_ico = fs[\"favicon.ico\"];\nconsole.log(JSON.stringify(fs, null, \"\\n \\t\"));\n```\n\n## Content\n\n- [Usage](https://github.com/nathanjhood/noderc#usage)\n  - [Build your own](https://github.com/nathanjhood/noderc#build-your-own)\n  - [Requirements](https://github.com/nathanjhood/noderc#requirements)\n- [Hacking](https://github.com/nathanjhood/noderc#hacking)\n- [Docs](https://github.com/nathanjhood/noderc#usage)\n  - [```noderc.open()```](https://github.com/nathanjhood/noderc#nodercopen)\n  - [```noderc.isFile()```](https://github.com/nathanjhood/noderc#nodercisfile)\n  - [```noderc.isDirectory()```](https://github.com/nathanjhood/noderc#nodercisdirectory)\n  - [```noderc.exists()```](https://github.com/nathanjhood/noderc#nodercexists)\n  - [```noderc.compare()```](https://github.com/nathanjhood/noderc#noderccompare)\n  - [```noderc.compareSize()```](https://github.com/nathanjhood/noderc#noderccomparesize)\n  - [```noderc.compareContent()```](https://github.com/nathanjhood/noderc#noderccomparecontent)\n  - [```noderc.getFileSystemObject()```](https://github.com/nathanjhood/noderc#noderccompare)\n- [Acknowledgments](https://github.com/nathanjhood/noderc#acknowledgments)\n\n## Usage\n\nTo see how to serve binary-compiled resources as Javascript objects, follow these steps:\n\n- clone the repo, and ```cd``` into it\n- run ```npm run install``` or ```yarn install``` to install the dependencies and build the test project\n- the file ```/test/index.js``` calls some functions that are defined and exported in ```/src/noderc.cpp```\n- the actual files and directories to be compiled are specified in the [```CMakeLists.txt```](https://github.com/nathanjhood/noderc/blob/main/CMakeLists.txt#L29C11-L29C25) file:\n\n```.cmake\nlist (APPEND RESOURCES\n  # Resources to compile (add more as you please)...\n  favicon.ico\n  tst.txt\n)\n```\n\n- the resources added to the above list shall be available in Javascript with ```noderc.open(\"filename\")```.\n- [see the test file](https://github.com/nathanjhood/noderc/blob/main/test/index.js) for further functionality, such as testing if a given filename or directory exists (within the compiled library), or whether a file on disk matches the compiled resource (an excellent safety feature).\n- run the tests with ```npm run start``` or ```yarn start```\n\n## Build your own\n\nTo build your own custom resource library and use it in your own NodeJs projects:\n\n- fork this repo\n- customize the [```RESOURCES``` to be compiled in ```CMakeLists.txt```](https://github.com/nathanjhood/noderc/blob/main/CMakeLists.txt#L29C11-L29C25) - they also need to be under version control\n- push your changes to your fork\n- add the URL of your fork to the ```package.json``` dependencies of the NodeJs project which will consume your library\n```.json\n\"dependencies\": {\n    \"@\u003cGithubUserName\u003e/noderc\": \"https://github.com/\u003cGithubUserName\u003e/noderc\",\n    // etc...\n}\n```\n- run ```npm run install``` or ```yarn install``` in your NodeJs project to acquire and build your library\n- your library will be available in your NodeJs project by requiring/importing:\n\n```.js\nconst noderc = require(\"@\u003cGithubUserName\u003e/noderc\")\n\n// or\n\nimport noderc from '@\u003cGithubUserName\u003e/noderc'\n\n// then\n\nconst my_compiled_resource = noderc.open(\"somefile.ext\")\n```\n\n## Requirements\n\n- NodeJs\n- CMake\n- A C/C++ compiler toolchain (GCC, LLVM, MSVC...)\n- A build generator (Ninja, Make, MSVC...)\n\nThe remaining dependencies either ship with the repo (such as the 'CMakeRC.cmake' file), or are acquired when running ```npm install``` or ```yarn install``` to initialize the project.\n\n## Hacking\n\n### Trying to build the NodeJs addon manually?\n\nWhen building this project from the npm/yarn command, the package ```cmake-js``` is invoked, which then reads from the same build script - ```CMakeLists.txt``` - as the CMake CLI does in a typical build scenario. However, ```cmake-js``` also passes an argument to the compiler equivalent to passing ```-DCMAKE_CXX_FLAGS:STRING=-DBUILDING_NODE_EXTENSION``` on the command line. You may also pass the above arg manually when building with CMake directly on the command line, as long as you have already done ```npm install``` or ```yarn install``` to acquire these headers; they should be found in the usual ```node_modules``` folder at the project root.\n\nYou will also need to install the ```cmake-js``` package globally in order to acquire necessary NodeJS development files; just run ```npm -g install cmake-js``` or ```yarn global add cmake-js``` before building. Note that the entire content of 'noderc.cpp' is guarded by requiring ```napi.h``` to be found and ```BUILDING_NODE_EXTENSION``` to be defined. See the next section if you can't find ```napi.h```.\n\n### \"Where is 'napi.h'?\"\n\nWhen building the NodeJS addon, your IDE might not find the ```\u003cnapi.h\u003e``` file, even when building successfully. The file(s) you need should be in the ```node_modules``` directory, under ```node-api-headers/include``` (C headers for NodeJs) and ```node-addon-api``` (C++ headers which wrap the C headers)\\*. The build script(s) will pick them up automatically, but your IDE might not. You just need to add these two directories appropriately to your IDE's intellisense engine path.\n\nVSCode with C++ extension example:\n\n```.json\n// .vscode/c_cpp_properties.json\n{\n  \"configurations\": [\n    {\n      \"name\": \"Linux\",\n      \"includePath\": [\n        \"${workspaceFolder}/**\",\n        \"node_modules/node-addon-api\",\n        \"node_modules/node-api-headers/include\"\n      ],\n      \"defines\": [],\n      \"compilerPath\": \"/usr/bin/g++\",\n      \"cStandard\": \"c17\",\n      \"cppStandard\": \"c++14\",\n      \"intelliSenseMode\": \"linux-gcc-x64\",\n      \"configurationProvider\": \"ms-vscode.cmake-tools\"\n    }\n  ],\n  \"version\": 4\n}\n\n```\n\n\\*Important distinction: ```\u003cnapi.h\u003e``` is the C++ addon header, and is ABI-stable.\n\n### Node versions, nvm, and ABI stability\n\nIf you are using nvm (node version manager), or have different Node installations on your system, Node addons written using the ```Node API``` C headers will complain that the Node version used during build is different to the one attempting to run the built module. The ```Node Addon API``` C++  header provides an ABI stability promise, which circumvents this issue.\n\nWhen choosing to build an addon using the Node ```Node API``` C headers directly, you must build against the same Node version that you intend to run on.\n\nWith this in mind, ```noderc``` is written using ```Node Addon API``` in C++; you should not experience any issues with differing Node versions and nvm when building this project, thanks to the ```Node Addon API```'s' ABI stability promise.\n\n## Docs\n\nThe ```build``` step generates a dynamic library in the output directory. The contents of the dynamic library work like an 'embedded' file system - the files listed in [```RESOURCES```](https://github.com/nathanjhood/noderc/blob/main/CMakeLists.txt#L29C11-L29C25) are compiled in to this embedded filesystem, making their contents available as a ```file``` and their path prefixes available as a ```directory``` tree.\n\nA second library is generated by the ```build``` step, which contains an interface that connects the embedded filesystem library to the NodeJs Addon interface, all written in C++.\n\nThe functionality exposed by this interface just provides and exports Javascript-side wrappers around the [CMakeRC](https://github.com/vector-of-bool/cmrc.git) functions.\n\nAll of the currently-implemented functionality available on the Javascript is described below.\n\n## ```noderc.open()```\n\n```.js\n(method) noderc.open(path: string): string\n```\nOpens and returns a non-directory ```file``` object at ```path```, or throws ```std::system_error()``` (as a Javascript exception) on error. The ```file``` object, if it exists, is returned as a Javascript ```string``` (for now).\n\nExample:\n```.js\nconst favicon = noderc.open(\"favicon.ico\")\n```\n\nThe ```file``` objects returned by this method are the ones added to the [```RESOURCES``` list in ```CMakeLists.txt```](https://github.com/nathanjhood/noderc/blob/main/CMakeLists.txt#L29C11-L29C25). It should be possible to add basically *any* file to this list and make it available in Javascript using ```noderc.open(\"filename.ext\")```.\n\nWhen adding to ```RESOURCES```, the items you want to compile should be specified *relative to the project root folder*, ideally. CMakeRC uses the full filename specified in this list, *including any path prefixes*, when making the compiled resource available via ```noderc.open()```.\n\nThis means that you could add the following entries to the list to be compiled (in ```CMakeLists.txt```):\n```.cmake\nlist (APPEND RESOURCES\n\n  # Resources to compile (add/remove as you please)...\n  favicon.ico\n  tst.txt\n  test/views/layout.pug # note that the path prefix was used here...\n)\n```\n\nNow, the added ```layout.pug``` file should be available via ```noderc.open()```, but you must specifiy the entire path prefix in order to find it:\n```.js\nconst tst_txt     = noderc.open(\"tst.txt\");\nconst favicon_ico = noderc.open(\"favicon.ico\");\nconst layout_pug  = noderc.open(\"test/views/layout.pug\"); // path prefix required\n```\n\n## ```noderc.isFile()```\n\n```.js\n(method) noderc.isFile(path: string): boolean\n```\n\nReturns ```true``` if the given ```path``` names a regular file, ```false``` otherwise.\n\nExample:\n```.js\nconst thisWillBeFalse = noderc.isFile(\"test/views\")\nconst thisWillBeTrue  = noderc.isFile(\"test/views/layout.pug\")\n```\n\n## ```noderc.isDirectory()```\n\n```.js\n(method) noderc.isDirectory(path: string): boolean\n```\n\nReturns ```true``` if the given ```path``` names a directory, ```false``` otherwise.\n\nExample:\n```.js\nconst thisWillBeFalse = noderc.isDirectory(\"test/views/layout.pug\")\nconst thisWillBeTrue  = noderc.isDirectory(\"test/views\")\n```\n\n## ```noderc.exists()```\n\n```.js\n(method) noderc.exists(path: string): boolean\n```\n\nReturns ```true``` if the given ```path``` names an existing file or directory, ```false``` otherwise.\n\nExample:\n```.js\n// missing path prefix....\nconst thisWillBeFalse  = noderc.exists(\"layout.pug\")\n\n// is a file\nconst thisWillBeTrueA  = noderc.exists(\"test/views/layout.pug\")\n\n// is a directory\nconst thisWillBeTrueB  = noderc.exists(\"test/views\")\n```\n\n## ```noderc.compare()```\n\n```.js\n(method) noderc.compare(file: string, path: string): boolean\n```\n\nCompare a ```file``` on disk to a  compiled resource at ```path```; returns ```false``` if the ```file``` is not the same size (in bytes) as the compiled resource at ```path```, or if the content of ```file``` (in bytes) does not match the content of the compiled resource at ```path```. Otherwise, returns true. Can also print to ```STDOUT```.\n\nExample:\n\nSay we have a file located on disk at ```/home/myconfig.cfg```, and that we compile it with ```noderc```, so that the file is accessible at ```noderc.open(\"myconfig.cfg\")```.\n\ntest = true, *if* the file (param A) matches the resource (param B)\n```.js\nconst test = noderc.compare(\"/home/myconfig.cfg\", \"myconfig.cfg\")\n```\ntest = false, *if* the file (param A) does not match the resource (param B)\n```.js\nconst test = noderc.compare(\"/backup/my_backup_config.cfg\", \"myconfig.cfg\")\n```\n\n## ```noderc.compareSize()```\n\n```.js\n(method) noderc.compareSize(file: string, path: string): boolean\n```\n\nCompare a ```file``` on disk to a  compiled resource at ```path```; returns ```false``` if the ```file``` is not the same size (in bytes) as the compiled resource at ```path```. Otherwise, returns true. Can also print to ```STDOUT```.\n\nExample:\n```.js\nconst trueIfSameSize = noderc.compareSize(\"/home/myconfig.cfg\", \"myconfig.cfg\")\n```\n\n## ```noderc.compareContent()```\n\n```.js\n(method) noderc.compareContent(file: string, path: string): boolean\n```\n\nCompare a ```file``` on disk to a  compiled resource at ```path```; returns ```false``` if the ```file``` does not match (in byte-to-byte comparison) the compiled resource at ```path```. Otherwise, returns true. Can also print to ```STDOUT```.\n\nExample:\n```.js\nconst trueIfSameBytes = noderc.compareContent(\"/home/myconfig.cfg\", \"myconfig.cfg\")\n```\n\n## ```noderc.getFileSystemObject()```\n\n```.js\n(method) noderc.getFileSystemObject(): object\n```\n\nReturns the entire ```cmrc::embedded_filesystem()``` as a Javascript ```object```.\n\nJavascript ```object``` semantics can then be used to access the entries in the embedded filesystem in various ways.\n\nExamples:\n\n```.js\n// Cast the entire embedded filesystem object to JSON for inspection\nconst fs_to_json = JSON.stringify(noderc.getFileSystemObject(), null, \"\\n \\t\")\nconsole.log(fs_to_json)\n```\n\n```.js\n// Cast a single embedded filesystem entry to a Javascript object\nconst fs = noderc.getFileSystemObject();\nconst tst_txt = fs[\"tst.txt\"];\n```\n\n## Thanks for reading!\n\n[Nathan J. Hood](https://github.com/nathanjhood)\n\n## Acknowledgements\n\n- [CMakeRC - Copyright 2018 vector-of-bool](https://github.com/vector-of-bool/cmrc.git)\n- [CMakeRC Blog article](https://vector-of-bool.github.io/2017/01/21/cmrc.html)\n- [Node-API Resource](https://nodejs.github.io/node-addon-examples/)\n- [Node Addon API documentation](https://github.com/nodejs/node-addon-api#api-documentation)\n\nPlease note that the version of CMakeRC in the project root has been slightly enhanced to provide intellisense, and to ensure a consistent C++ exceptions policy is used throughout the codebase. These changes may be reverted in a future update which intends to incorporate throwing CMakeRC's exceptions as a ```Napi::Exception``` to the Javascript side.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnathanjhood%2Fnoderc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnathanjhood%2Fnoderc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnathanjhood%2Fnoderc/lists"}