{"id":17855601,"url":"https://github.com/nebrius/commascript","last_synced_at":"2025-09-20T22:32:52.972Z","repository":{"id":21557908,"uuid":"24877642","full_name":"nebrius/commascript","owner":"nebrius","description":"A statically typed, backwards compatible dialect of JavaScript ","archived":false,"fork":false,"pushed_at":"2017-04-21T07:23:33.000Z","size":482,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-12-29T18:03:10.596Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/nebrius.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}},"created_at":"2014-10-07T05:14:08.000Z","updated_at":"2020-10-02T01:40:28.000Z","dependencies_parsed_at":"2022-07-16T14:30:30.213Z","dependency_job_id":null,"html_url":"https://github.com/nebrius/commascript","commit_stats":null,"previous_names":["bryan-m-hughes/commascript"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nebrius%2Fcommascript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nebrius%2Fcommascript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nebrius%2Fcommascript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nebrius%2Fcommascript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nebrius","download_url":"https://codeload.github.com/nebrius/commascript/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233682445,"owners_count":18713552,"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":"2024-10-28T02:23:45.156Z","updated_at":"2025-09-20T22:32:47.648Z","avatar_url":"https://github.com/nebrius.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"CommaScript\n===========\n\n[![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/)\n\nCommaScript is a backwards compatible dialect of JavaScript that provides localized, implicit static typing in\nJavaScript while still feeling like JavaScript.\n\n**WARNING:** This is a work in progress! The current version of the software is ALPHA quality\n\n**Note:** This hasn't been updated in some time. I would love to come back to it and give it the eS6 treatment someday, but I don't forsee having the time to really invest in this projectto make it viable. As such, consider this abandonware.\n\n## Table of Contents\n* [Design Goals](#design-goals)\n* [Compilation](#compilation)\n* [Examples](#examples)\n   * [Primitives](#primitives)\n   * [Objects](#objects)\n   * [Functions](#functions)\n   * [Constructors](#constructors)\n   * [Arrays](#arrays)\n* [Interfaces](#interfaces)\n* [Scoping](#scoping)\n* [Future Goals](#future-goals)\n* [License](#license)\n\n## Design Goals\n\nThere have been several attempts at providing static typing in JavaScript, such\nas [TypeScript](http://www.typescriptlang.org/) and [Dart](http://www.dartlang.org/).\nBoth languages are great languages, but they suffer from one fatal flaw: they aren't\nJavaScript!\n\nMozilla has another attempt at statically typed JavaScript called [asm.js](http://asmjs.org/)\nwhich is a proper subset of JavaScript, meaning it will run in all JavaScript\nengines, even the ones that don't support asm.js. The primary flaw with asm.js is\nthat it looks a lot like assembly, and isn't meant to be programmed in directly.\n\nCommaScript aims to have the backwards compatibility of asm.js combined with the\nexpressiveness of TypeScript and Dart. Specifically, CommaScript has the\nfollowing goals\n* 100% JavaScript compliant syntax\n* Compiled and uncompiled CommaScript code is semantically identical\n    * As a result, uncompiled CommaScript code runs the same as compiled code\n* CommaScript code should still feel like JavaScript as much as possible\n    * The type system should be an aid to developers, not get in their way\n\n## Compilation\n\nCommaScript code can be run through an analyzer that will verify the type correctness\nof the code. To install the analyzer:\n\n```\nnpm install commascript\n```\n\nTo run the analyzer on foo.js\n\n```\ncommascript foo.js\n```\n\nAny type errors are output to the terminal.\n\n## Examples\n\nFor detailed specification information, view the [Formal Specification](grammar.md)\n\n### Primitives\n\nTo create a variable typed as a primitive, simply give that variable an initial value:\n\n```JavaScript\nvar x = 0;\n```\n\nOnce defined, all other uses of x must be numerical:\n\n```JavaScript\n// This is allowed\nx = 10;\n\n// So is this\nx++;\n\n// And this\nvar y = x + 10;\n\n// But this will generate a compile-time error\nx = 'boo';\n```\n\nNote that undefined values are not allowed in CommaScript.\n\n### Objects\n\nWhen working with object literals, it's usually just as easy as working with\nprimitives:\n\n```JavaScript\nvar obj = {\n  'bar': 'hello world',\n  'baz': 10\n};\n```\n\nWe can also set individual properties on the object:\n\n```JavaScript\nobj.bar = 'goodbye';\nobj.baz = 20;\n```\n\nObjects and their properties are strictly typed, meaning that a compile time\nerror is generated if you try to assign the wrong type of value to a property:\n\n```JavaScript\nobj.bar = false;\n```\n\nIf we try and access a non-existent property, perhaps because we mistyped its\nname, then CommaScript will also generate an error:\n\n```JavaScript\nobj.bax = 10;\n```\n\n### Functions\n\nFunctions are declared implicitly, just like objects:\n\n```JavaScript\nfunction foo(a, b) {\n  return a * b;\n}\n```\n\nCommaScript will infer the return type and the argument type(s), if any. In this example, the two arguments are being\nmultiplied together, which means that the arguments must both be numbers. Two numbers multiplied together produces another\nnumber, so the return type must be a number.\n\nFunctions that return undefined in JavaScript are considered by CommaScript to not have a value, akin to void in\nC/C++/Java. Trying to assign the return value of a \"void\" function is an error in CommaScript.\n\nFunctions are called as normal, but with type checking.\n\n```JavaScript\n// This will work fine\nfoo(1, 2);\n\n// As will this\nvar r = 0;\nr += foo(1, 2);\n\n// But not this\nfoo('hello', 'world');\n\n// Or this\nvar s = '';\ns = foo(1, 2);\n```\n\nBut what happens if the types cannot be inferred, such as with the example below?\n\n```JavaScript\nfunction foo(a, b) {\n  return a + b; // Everything can be added together, since everything can be converted to a string\n}\n```\n\nAll you have to do is leave the definition ambiguous. This introduces a new concept in CommaScript: generics. Generics in\nCommaScript work similarly to [generics in Java](http://en.wikipedia.org/wiki/Generics_in_Java) or\n[templates in C++](http://en.wikipedia.org/wiki/Template_%28C%2B%2B%29). The type of the arguments and/or return type are\ndetermined by how the function is invoked:\n\n```JavaScript\nfunction foo(a, b) {\n  return a + b;\n}\n\n // Arguments and x are set to type \"number\"\nvar x = foo(1, 2);\n\n// First argument is set to type \"number\", second argument and y are set to type \"string\"\nvar y = foo(1, '2');\n\n// x and y are still statically typed\nx = 'hello'; // Generates an error\ny = false; // Generates an error\n```\n\n### Constructors\n\nInstantiable objects (things you create with ```new```) are supported in CommaScript. What differentiates a constructor\nfrom a regular function is that a constructor is used with the ```new``` operator, while functions are not. Also, you\ncannot reference a functions prototype, but you can reference a constructors prototype.\n\n```JavaScript\nfunction foo(arg) {\n  this.arg = arg;\n}\nfoo.prototype.getArg = function() {\n  return this.arg;\n}\n\n// Then we can create an object\nvar a = new foo(10);\n\n// And access its methods\nvar b = 5 + a.getArg();\n\n// But only if they exist\nvar c = a.fail; // Generates an error\n\n// And the types are correct\nvar d = false \u0026\u0026 a.getArg(); // Generates an error\n\n// The call to the object constructor must also be typed correctly\nvar e = new foo(); // Generates an error\n```\n\n### Arrays\n\nArrays are considerably restricted compared to normal JavaScript arrays. Every element in a CommaScript array must be of a homogeneous type:\n\n```JavaScript\nvar foo = [1, 2, 3]; // Creates an array of numbers\n\n// Then we can do\nfoo.push(4);\n\n// We can also do\nfoo[4] = 5;\n\n// But not\nfoo[5] = 'hello world';\n\n// Or\nfoo.bar = 'baz';\n```\n\n## Interfaces\n\nThere are some instances where the above syntax is not flexible enough. This is where we introduce the concept of\ninterfaces in CommaScript. An interface specifies a _named_ or _unnamed_ type that can be used in a number of circumstances.\n\nAn interface is defined using a special syntax that uses the comma operator (also called the sequence operator). In\ncase you were wondering, this is where CommaScript gets its name. An interface definition has the following structure:\n\n```JavaScript\n('define(object|function|array[, typename])', definition[, value]);\n```\n\nComplementing interface definitions are cast statements:\n\n```JavaScript\n('cast(typename)', value)\n```\n\nAs a motivating example, what if we want to declare an object and give it an initial value of ```null```? Since we cannot\ninfer the object type from ```null```, we create an named object type and then cast ```null``` to that type.\n\n```JavaScript\n'use commascript';\n\n('define(object, MyObject)', {\n  properties: {\n    'bar': 'string',\n    'baz': 'number'\n  }\n});\n\nvar obj = ('cast(MyObject)', null);\n```\n\nWe can later assign an instance of the object to the variable:\n\n```JavaScript\nobj = {\n  'bar': 'hello world',\n  'baz': 10\n};\n```\n\nRemember back to the case where function definitions are ambiguous. What if you don't want your function to be generic?\nYou can create an named function type and then define a function with the same name:\n\n```JavaScript\n('define(function, MyFunction)', {\n  returnType: 'number',\n  argumentTypes: [\n    'number',\n    'number'\n  ]\n});\n\nvar foo = ('cast(MyFunction)', function (a, b) {\n    return a + b;\n});\n\n// Then you can do\nvar x = 5 + foo(1, 2);\n\n// But not\nvar y = '';\ny = foo(1, '2');\n```\n\nWe can also specify a constructor interface:\n\n```JavaScript\n('define(constructor, MyConstructor)', {\n  argumentTypes: [\n    'string'\n  ],\n  properties: {\n    getArg: ('define(function)', {\n        returnType: 'string'\n    })\n  }\n});\n\nvar foo = ('cast(MyConstructor)', function (arg) {\n  this.arg = arg;\n}\nfoo.prototype.getArg = function() {\n  return this.arg;\n}\n\n// Then we can create an object\nvar a = new foo('Hello');\n```\n\nA new feature is introduced inside the interface definition, an unnamed type. An unnamed type definition is an interface\ndefinition that is used inside of a comma declaration. Any define or cast operation that takes a named type can also take\nan inlined, unnamed type definition.\n\nWhat do you do if you want to create an empty array? In this case the array type cannot be inferred, so you created a\nnamed array type:\n\n```JavaScript\n('define(array, MyArray)', {\n   elementType: 'number'\n});\n\nvar foo = ('cast(MyArray)', []);\n\nfoo.push(10);\n```\n\n## Scoping\n\nCommaScript code is localized to the current _block_ and must be enabled with a using directive, just like strict mode:\n\n```JavaScript\n'use commascript';\n```\n\nThis means that you can mix and match CommaScript code with non-CommaScript code:\n\n```JavaScript\nfunction foo() {\n  var x = true;\n  x = 10;\n  if (x) {\n    return true;\n  }\n  return 'hello';\n}\n\nfunction bar() {\n  'use commascript';\n  var x = 10;\n  return x \u0026\u0026 false; // Generates an error\n}\n\nfoo(); // Generates no errors\nbar();\n```\n\nYou can also localize CommaScript to non-function blocks:\n\n```JavaScript\nif (strict) {\n  'use commascript';\n  var x = 10;\n  x = 'fail'; // Generates an error\n} else {\n  var x = 10;\n  x = 'fail'; // Does NOT generate an error\n}\n```\n\nOnce a block is declared as being CommaScript, all inner blocks are also CommaScript:\n\n```JavaScript\nfunction foo() {\n  'use commascript';\n  function bar() {\n    // This is also CommaScript code\n  }\n  bar();\n}\n```\n\nSo how do you call a CommaScript function from non-CommaScript code? Create a CommaScript block that contains the function and create named types for the function and arguments, if any. It is up to the programmer to ensure that CommaScript code is being called correctly:\n\n```JavaScript\n\n{\n  'use commascript';\n\n  ('define(object, MyCommaScriptObject)', {\n    properties: {\n      foo: 'string',\n      bar: 'string'\n    }\n  });\n\n  ('define(function, MyCommaScriptFunction)', {\n    returnType: 'string',\n    argumentTypes: [\n      'number',\n      'MyCommaScriptObject'\n    ]\n  });\n\n  var myFunction = ('cast(MyCommaScriptFunction)', function(num, obj) {\n    // Do stuff\n    return 'hello';\n  });\n}\n\nmyFunction(10, {\n  foo: 'foo',\n  bar: 'bar'\n});\n```\n\nYou can also declare commascript just inside of a function, which causes the function to be treated as a generic function:\n\n```JavaScript\nfunction myFunction(num, obj) {\n  'use commascript';\n  // Do stuff\n  return 'hello';\n}\n\nmyFunction(10, {\n  foo: 'foo',\n  bar: 'bar'\n});\n```\n\nIf you want the function to have stricter type checking, the use the former method way of declaring commascript code.\n\nConversely, how do you call a non-CommaScript function from CommaScript code? Just create a named type for the non-CommaScript function. It is up to the programmer to ensure that the non-CommaScript function conforms to the named type.\n\n```JavaScript\n'use commascript';\n\n('extern(object, console)', {\n  properties: {\n    log: ('define(function)', {\n      argumentTypes: [\n        'string'\n      ]\n    }),\n    warn: ('define(function)', {\n      argumentTypes: [\n        'string'\n      ]\n    }),\n    error: ('define(function)', {\n      argumentTypes: [\n        'string'\n      ]\n    })\n  }\n});\n\nconsole.log('hi');\n```\n\nThis latest example introduces a new trick: extern instance definitions. An extern definition has the same syntax as an object type definition, with the difference being that externs cannot be used in cast definitions and do not require an instantiation. Think of it like ```extern``` in C/C++.\n\nWhen creating an extern type, it is not necessary to create a 100% complete definition for it. Indeed this would be impossible for most external objects because they do not conform to CommaScript interface restrictions. It is advisable to only define what you need to use from the extern object/function.\n\n## Future Goals\n\nOnce the basic compiler is implemented and the spec solidified, there are a few other\ngoals for the project:\n* Implement an LLVM frontend for CommaScript that will allow it to be compiled to\nnative code, or to asm.js\n* Implement CommaScript definitions for a few well known libraries and APIs, such\nas node.js and the browser DOM\n    * These definitions will most likely be proper subsets of the full APIs\n* Implement customized versions of CommonJS and RequireJS that can perform validation\nof source files when they are require()'d\n\nLicense\n=======\n\nThe MIT License (MIT)\n\nCopyright (c) 2013-2014 Bryan Hughes bryan@theoreticalideations.com (https://theoreticalideations.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnebrius%2Fcommascript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnebrius%2Fcommascript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnebrius%2Fcommascript/lists"}