{"id":26057795,"url":"https://github.com/feenkcom/jslink","last_synced_at":"2025-10-10T07:09:01.511Z","repository":{"id":38410195,"uuid":"239713788","full_name":"feenkcom/JSLink","owner":"feenkcom","description":"A bridge between Pharo and JavaScript","archived":false,"fork":false,"pushed_at":"2023-12-19T11:01:03.000Z","size":1125,"stargazers_count":9,"open_issues_count":2,"forks_count":1,"subscribers_count":13,"default_branch":"main","last_synced_at":"2023-12-19T14:22:05.937Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Smalltalk","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/feenkcom.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}},"created_at":"2020-02-11T08:37:57.000Z","updated_at":"2023-12-19T14:22:12.885Z","dependencies_parsed_at":"2023-12-19T14:22:11.686Z","dependency_job_id":"32bbb99a-8519-4faa-ab53-7a3b967e53e7","html_url":"https://github.com/feenkcom/JSLink","commit_stats":null,"previous_names":[],"tags_count":308,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feenkcom%2FJSLink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feenkcom%2FJSLink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feenkcom%2FJSLink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feenkcom%2FJSLink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/feenkcom","download_url":"https://codeload.github.com/feenkcom/JSLink/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242546038,"owners_count":20147096,"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":[],"created_at":"2025-03-08T11:59:01.557Z","updated_at":"2025-10-10T07:08:56.493Z","avatar_url":"https://github.com/feenkcom.png","language":"Smalltalk","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JSLink\n\nJSLink provides a mechanism for Pharo to communicate with libraries and applications implemented in node.js.\n\n- [Getting Started](#getting-started)\n\t- [Installation](#installation)\n\t- [First statements](#first-statements)\n\t- [Programmatic Use](#programmatic-use)\n- [Garbage Collection](#garbage-collection)\n- [Callbacks](#callbacks)\n- [Automated Tests](#automated-tests)\n- [ToDo](#todo)\n- [Futures](#futures)\n- [Acknowledgements and Thanks](#acknowledgements-and-thanks)\n\n\n## Getting Started\n\n\n### Installation\n\nRequirements:\n\nJSLink has been tested with:\n\n- Pharo 8\n- node.js 12.x\n\nTo install JSLink in an existing Gtoolkit image:\n\n```smalltalk\nEpMonitor disableDuring: [ \nMetacello new\n\trepository: 'github://feenkcom/gtoolkit-remote/src';\n\tbaseline: 'Gt4JSLink';\n\tload ]\n```\n\n\nTo install JSLink in a vanilla Pharo image:\n\n```smalltalk\nEpMonitor disableDuring: [ \nMetacello new\n\trepository: 'github://feenkcom/JSlink/src';\n\tbaseline: 'JavaScriptLink';\n\tload ]\n```\n\n\n### First statements\n\nWhen first running JSLink it is worthwhile starting Pharo from the command line so you can monitor the output.\n\nOpen a playground in [Gtoolkit](https://gtoolkit.com/) and start the JSLinkApplication:\n\n![Start JSLink](doc/images/Start_JSLink.png)\n\nThis will automatically install all the dependent modules with `npm`:\n\n```\n$ vmgt/gtoolkit Pharo.image eval --interactive --no-quit \"GtWorld open.\"\nGtWorld\n[Glutin] Profile #0 worked\n[Glutin] Profile #0 worked\nloadDep:fsevents → 304    ▌ ╢███████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░╟\nWARN engine fsevents@2.1.2: wanted: {\"node\":\"^8.16.0 || ^10.6.0 || \u003e=11.0.0\"} (current: {\"node\":\"8.10loadDep:react-is → header ▐ ╢███████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░╟\nloadDep:execa → resolveWi ▐ ╢███████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░╟\nWARN engine execa@3.4.0: wanted: {\"node\":\"^8.12.0 || \u003e=9.7.0\"} (current: {\"node\":\"8.10.0\",\"npm\":\"3.5.loadDep:strip-final-newli ▐ ╢███████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░╟\nWARN engine human-signals@1.1.1: wanted: {\"node\":\"\u003e=8.12.0\"} (current: {\"node\":\"8.10.0\",\"npm\":\"3.5.2\"\n\u003e sqlite3@4.1.1 install /home/alistair/pharo8/so07/pharo-local/iceberg/feenkcom/JSlink/js/node_modules/sqlite3\n\u003e node-pre-gyp install --fallback-to-build\n...\n```\n\nWe now evaluate our first expression in JavaScript:\n\n![First Object](doc/images/First_Object.png)\n\nAfter typing the code in to the playground it is evaluated by pressing the play \u0026 inspect button:\n\n![Play \u0026 Inspect button](doc/images/playinspect.png)\n\nFrom here we can navigate through the attributes of the object in the same way as when inspecting pharo objects.\n\nIf the value of the attribute is a non-primitive object, a proxy will be returned, if it is a primitive, it will be returned directly:\n\n![Inspect Primitive](doc/images/Inspect_Primitive.png)\n\nWhen evaluating statements in a proxy object's playground, `this` is bound to the proxy object:\n\n![this bound](doc/images/this_bound.png)\n\nThe node.js server can then be stopped with:\n\n```smalltalk\nJSLinkApplication stop.\n```\n\n\n### Programatic Use\n\nSo far we have been using a global instance of JSLink, however it is possible to have multiple servers running concurrently through the use of private instances.\n\nFor this example we'll create an Excel spreadsheet by installing and using the existing `excel4node` module.\n\nTo install the module:\n\n```smalltalk\njslink := JSLinkApplication withDefaultSettings.\njslink start.\njslink installModule: 'excel4node'.\n```\n\nJSLink allows JavaScript code to be supplied in two ways:\n\n1. Strings of JavaScript code, and\n1. AST objects generated using the [JavaScriptGenerator package](https://github.com/feenkcom/JavaScriptGenerator/)\n\nFirst, using strings:\n\n```smalltalk\n\"Start JSLink\"\njslink := JSLinkApplication withDefaultSettings.\njslink start.\n\n\"Ensure that the 'excel4node' module is installed.\"\njslink installModule: 'excel4node'\n\n\"Create the spreadsheet and worksheet\"\nworksheet := jslink newCommandFactory\n\t\u003c\u003c 'const excel = require(''excel4node'')';\n\t\u003c\u003c 'let workbook = new excel.Workbook()';\n\t\u003c\u003c 'let worksheet = workbook.addWorksheet(''HW'')';\n\t\u003c\u003c 'worksheet';\n\tsendAndWait.\n\n\"Write Hello, World!\"\nworksheet newCommandFactory\n\t\u003c\u003c 'this.cell(2, 2).string(\"Hello, World!\")';\n\tsendAndWait.\n\n\"Save the spreadsheet\"\nworksheet newCommandFactory\n\t\u003c\u003c 'this.wb.write(\"hw.xlsx\")';\n\tsendAndWait.\n\n\"Stop the server\"\njslink stop\n```\n\n![Hello, World! with strings](doc/images/helloworld_strings.png)\n\n\nSecond, using JavaScript generated with `JavaScriptGenerator`:\n\n```smalltalk\n\"Start JSLink\"\njslink := JSLinkApplication withDefaultSettings.\njslink start.\n\n\"Ensure that the 'excel4node' module is installed.\"\njslink installModule: 'excel4node'\n\n\"Create the spreadsheet and worksheet\"\nexcel := #excel asJSGIdentifier.\nwb := #wb asJSGIdentifier.\nws := #ws asJSGIdentifier.\nworksheet := jslink newCommandFactory\n\t\u003c\u003c (excel \u003c- #'excel4node' require) beLetDeclaration;\n\t\u003c\u003c (wb \u003c- (excel =\u003e #Workbook) call new) beLetDeclaration;\n\t\u003c\u003c (ws \u003c- ((wb =\u003e #addWorksheet) callWith: { 'HW' })) beLetDeclaration;\n\t\u003c\u003c 'ws';\n\tsendAndWait.\n\n\"Write Hello, World!\"\nworksheet newCommandFactory\n\t\u003c\u003c (((#this asJSGI =\u003e #cell callWith: { 2. 2. }) =\u003e #string) callWith: { 'Hello, World!'});\n\tsendAndWait.\n\n\"Save the spreadsheet\"\nworksheet newCommandFactory\n\t\u003c\u003c ((#this asJSGI =\u003e #wb =\u003e #write) callWith: { 'hw2.xlsx' });\n\tsendAndWait.\n\n\"Stop the server\"\njslink stop\n```\n\n\n![Hello, World! with JavaScriptGenerator](doc/images/helloworld_jsg.png)\n\n\n## Garbage Collection\n\nProxy objects register them selves for finalisation.  When they are garbage collected in Pharo they are automatically removed from the registry in the node.js server.\n\n\n## Callbacks\n\nCallbacks in to Pharo from node.js are supported through observables.\n\nSee `JSLinkSendCommandTest` for examples of setting up and using callbacks.\n\n\n## Automated Tests\n\nSee the 'JSLink-Tests` package.\n\n## ToDo\n\n`PythonBridge` supports communicating with the server using either HTTP or [MsgPack](https://msgpack.org/).  While the code has been left in the package, MsgPack is not yet supported.\n\n\n## Futures\n\nCurrently JSLink is specific to node.js.  Planned future work includes adding support for the debug port in node.js, to provide better program control, and adding support for browsers, initially Chrome, using their debug port.\n\n\n## Acknowledgements and Thanks\n\nThanks to the team at [ObjectProfile](http://www.objectprofile.com/) for making [PythonBridge](https://github.com/ObjectProfile/PythonBridge), on which JSLink is based, and to [Julien Delplanque](https://github.com/juliendelplanque) for [Python3Generator](https://github.com/juliendelplanque/Python3Generator), on which JavaScriptGenerator is based.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffeenkcom%2Fjslink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffeenkcom%2Fjslink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffeenkcom%2Fjslink/lists"}