Blog

  • rubric

    Rubric Monorepo

    Home of Rubric Labs

    This repo contains Rubric’s, UI library, docs, and code config.

    This makes it easier to

    • Share code across projects
    • Coordinate global style changes with a single PR
    • Skip common setup in new projects: Tailwind, Biome, Typescript, etc.

    What’s inside?

    This monorepo includes the following packages and apps:

    Packages

    Core framework packages for building agentic applications:

    Development and tooling:

    Apps

    Notable applications built with our framework:

    • rOS: Operating system for AI agents
    • chat: Real-time chat application
    • x: Core agent system with iOS integration
    • And more experimental applications

    Build

    To build all apps and packages, run:

    bun build

    Develop

    To develop all apps and packages:

    bun dev

    To develop a specific app:

    cd apps/[app_name]
    bun run dev

    Dependencies

    To add a dependency to a specific app:

    cd apps/[app_name]
    bun i dependency

    To add a global dependency:

    bun add -W dependency

    Technologies

    • Bun.js for fast JavaScript runtime and package management
    • TypeScript for static type checking
    • Next.js for full-stack React applications
    • Turborepo for monorepo management
    • Biome for fast, modern code linting and formatting

    License

    MIT

    Visit original content creator repository
    https://github.com/RubricLab/rubric

  • elephant

                                     Apache License
                               Version 2.0, January 2004
                            http://www.apache.org/licenses/
    
       TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
    
       1. Definitions.
    
          "License" shall mean the terms and conditions for use, reproduction,
          and distribution as defined by Sections 1 through 9 of this document.
    
          "Licensor" shall mean the copyright owner or entity authorized by
          the copyright owner that is granting the License.
    
          "Legal Entity" shall mean the union of the acting entity and all
          other entities that control, are controlled by, or are under common
          control with that entity. For the purposes of this definition,
          "control" means (i) the power, direct or indirect, to cause the
          direction or management of such entity, whether by contract or
          otherwise, or (ii) ownership of fifty percent (50%) or more of the
          outstanding shares, or (iii) beneficial ownership of such entity.
    
          "You" (or "Your") shall mean an individual or Legal Entity
          exercising permissions granted by this License.
    
          "Source" form shall mean the preferred form for making modifications,
          including but not limited to software source code, documentation
          source, and configuration files.
    
          "Object" form shall mean any form resulting from mechanical
          transformation or translation of a Source form, including but
          not limited to compiled object code, generated documentation,
          and conversions to other media types.
    
          "Work" shall mean the work of authorship, whether in Source or
          Object form, made available under the License, as indicated by a
          copyright notice that is included in or attached to the work
          (an example is provided in the Appendix below).
    
          "Derivative Works" shall mean any work, whether in Source or Object
          form, that is based on (or derived from) the Work and for which the
          editorial revisions, annotations, elaborations, or other modifications
          represent, as a whole, an original work of authorship. For the purposes
          of this License, Derivative Works shall not include works that remain
          separable from, or merely link (or bind by name) to the interfaces of,
          the Work and Derivative Works thereof.
    
          "Contribution" shall mean any work of authorship, including
          the original version of the Work and any modifications or additions
          to that Work or Derivative Works thereof, that is intentionally
          submitted to Licensor for inclusion in the Work by the copyright owner
          or by an individual or Legal Entity authorized to submit on behalf of
          the copyright owner. For the purposes of this definition, "submitted"
          means any form of electronic, verbal, or written communication sent
          to the Licensor or its representatives, including but not limited to
          communication on electronic mailing lists, source code control systems,
          and issue tracking systems that are managed by, or on behalf of, the
          Licensor for the purpose of discussing and improving the Work, but
          excluding communication that is conspicuously marked or otherwise
          designated in writing by the copyright owner as "Not a Contribution."
    
          "Contributor" shall mean Licensor and any individual or Legal Entity
          on behalf of whom a Contribution has been received by Licensor and
          subsequently incorporated within the Work.
    
       2. Grant of Copyright License. Subject to the terms and conditions of
          this License, each Contributor hereby grants to You a perpetual,
          worldwide, non-exclusive, no-charge, royalty-free, irrevocable
          copyright license to reproduce, prepare Derivative Works of,
          publicly display, publicly perform, sublicense, and distribute the
          Work and such Derivative Works in Source or Object form.
    
       3. Grant of Patent License. Subject to the terms and conditions of
          this License, each Contributor hereby grants to You a perpetual,
          worldwide, non-exclusive, no-charge, royalty-free, irrevocable
          (except as stated in this section) patent license to make, have made,
          use, offer to sell, sell, import, and otherwise transfer the Work,
          where such license applies only to those patent claims licensable
          by such Contributor that are necessarily infringed by their
          Contribution(s) alone or by combination of their Contribution(s)
          with the Work to which such Contribution(s) was submitted. If You
          institute patent litigation against any entity (including a
          cross-claim or counterclaim in a lawsuit) alleging that the Work
          or a Contribution incorporated within the Work constitutes direct
          or contributory patent infringement, then any patent licenses
          granted to You under this License for that Work shall terminate
          as of the date such litigation is filed.
    
       4. Redistribution. You may reproduce and distribute copies of the
          Work or Derivative Works thereof in any medium, with or without
          modifications, and in Source or Object form, provided that You
          meet the following conditions:
    
          (a) You must give any other recipients of the Work or
              Derivative Works a copy of this License; and
    
          (b) You must cause any modified files to carry prominent notices
              stating that You changed the files; and
    
          (c) You must retain, in the Source form of any Derivative Works
              that You distribute, all copyright, patent, trademark, and
              attribution notices from the Source form of the Work,
              excluding those notices that do not pertain to any part of
              the Derivative Works; and
    
          (d) If the Work includes a "NOTICE" text file as part of its
              distribution, then any Derivative Works that You distribute must
              include a readable copy of the attribution notices contained
              within such NOTICE file, excluding those notices that do not
              pertain to any part of the Derivative Works, in at least one
              of the following places: within a NOTICE text file distributed
              as part of the Derivative Works; within the Source form or
              documentation, if provided along with the Derivative Works; or,
              within a display generated by the Derivative Works, if and
              wherever such third-party notices normally appear. The contents
              of the NOTICE file are for informational purposes only and
              do not modify the License. You may add Your own attribution
              notices within Derivative Works that You distribute, alongside
              or as an addendum to the NOTICE text from the Work, provided
              that such additional attribution notices cannot be construed
              as modifying the License.
    
          You may add Your own copyright statement to Your modifications and
          may provide additional or different license terms and conditions
          for use, reproduction, or distribution of Your modifications, or
          for any such Derivative Works as a whole, provided Your use,
          reproduction, and distribution of the Work otherwise complies with
          the conditions stated in this License.
    
       5. Submission of Contributions. Unless You explicitly state otherwise,
          any Contribution intentionally submitted for inclusion in the Work
          by You to the Licensor shall be under the terms and conditions of
          this License, without any additional terms or conditions.
          Notwithstanding the above, nothing herein shall supersede or modify
          the terms of any separate license agreement you may have executed
          with Licensor regarding such Contributions.
    
       6. Trademarks. This License does not grant permission to use the trade
          names, trademarks, service marks, or product names of the Licensor,
          except as required for reasonable and customary use in describing the
          origin of the Work and reproducing the content of the NOTICE file.
    
       7. Disclaimer of Warranty. Unless required by applicable law or
          agreed to in writing, Licensor provides the Work (and each
          Contributor provides its Contributions) on an "AS IS" BASIS,
          WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
          implied, including, without limitation, any warranties or conditions
          of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
          PARTICULAR PURPOSE. You are solely responsible for determining the
          appropriateness of using or redistributing the Work and assume any
          risks associated with Your exercise of permissions under this License.
    
       8. Limitation of Liability. In no event and under no legal theory,
          whether in tort (including negligence), contract, or otherwise,
          unless required by applicable law (such as deliberate and grossly
          negligent acts) or agreed to in writing, shall any Contributor be
          liable to You for damages, including any direct, indirect, special,
          incidental, or consequential damages of any character arising as a
          result of this License or out of the use or inability to use the
          Work (including but not limited to damages for loss of goodwill,
          work stoppage, computer failure or malfunction, or any and all
          other commercial damages or losses), even if such Contributor
          has been advised of the possibility of such damages.
    
       9. Accepting Warranty or Additional Liability. While redistributing
          the Work or Derivative Works thereof, You may choose to offer,
          and charge a fee for, acceptance of support, warranty, indemnity,
          or other liability obligations and/or rights consistent with this
          License. However, in accepting such obligations, You may act only
          on Your own behalf and on Your sole responsibility, not on behalf
          of any other Contributor, and only if You agree to indemnify,
          defend, and hold each Contributor harmless for any liability
          incurred by, or claims asserted against, such Contributor by reason
          of your accepting any such warranty or additional liability.
    
       END OF TERMS AND CONDITIONS
    
       APPENDIX: How to apply the Apache License to your work.
    
          To apply the Apache License to your work, attach the following
          boilerplate notice, with the fields enclosed by brackets "[]"
          replaced with your own identifying information. (Don't include
          the brackets!)  The text should be enclosed in the appropriate
          comment syntax for the file format. We also recommend that a
          file or class name and description of purpose be included on the
          same "printed page" as the copyright notice for easier
          identification within third-party archives.
    
       Copyright [yyyy] [name of copyright owner]
    
       Licensed under the Apache License, Version 2.0 (the "License");
       you may not use this file except in compliance with the License.
       You may obtain a copy of the License at
    
           http://www.apache.org/licenses/LICENSE-2.0
    
       Unless required by applicable law or agreed to in writing, software
       distributed under the License is distributed on an "AS IS" BASIS,
       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       See the License for the specific language governing permissions and
       limitations under the License.
    

    Visit original content creator repository
    https://github.com/webus/elephant

  • push-down-field-refactoring

    Continuous Integration

    ℹ️ This repository is part of my Refactoring catalog based on Fowler’s book with the same title. Please see kaiosilveira/refactoring for more details.


    Push Down Field

    Before After
    class Employee {
      protected quota: string;
    }
    
    class Engineer extends Employee { ... }
    class Salesman extends Employee { ... }
    class Employee { ... }
    class Engineer extends Employee { ... }
    class Salesman extends Employee {
      private quota: string;
    }

    Inverse of: Pull Up Field

    As it often happens with class hierarchies, we have some specific fields that was firstly thought to be common to all subclasses, but end up being relevant just for some of those. This refactoring gives a glimpse of what to do in these cases.

    Working example

    Our working example is a straightforward Employee class hierarchy:

    classDiagram
        class Employee
        Employee <|-- Engineer
        Employee <|-- Salesman
    
        class Employee {
            name
            quota
        }
    
    Loading

    Our goal is to move the quota field down to Salesman, since it’s only used there.

    Test suite

    Our test suite covers the basic properties of Salesman:

    describe('Salesman', () => {
      it('should have a name', () => {
        const salesman = new Salesman('Kaio');
        expect(salesman.name).toBe('Kaio');
      });
    
      it('should have a quota', () => {
        const salesman = new Salesman('Kaio');
        expect(salesman.quota).toBe(1.5);
      });
    });

    That’s the minimum we need in place to get going.

    Steps

    We start by copying the quota field into Salesman:

    diff --git Salesman...
      constructor(name) {
        super(name, 1.5);
    +   this.quota = 1.5;
      }

    then we remove quota from Employee (and update the other subclass so they don’t need to provide this value any longer):

    diff --git Employee...
       constructor(name) {
    -    super(name, 0);
    +    super(name);
       }

    And that’s it!

    Commit history

    Below there’s the commit history for the steps detailed above.

    Commit SHA Message
    6b116ee copy quota field into Salesman
    afe975e remove quota field from Employee

    For the full commit history for this project, check the Commit History tab.

    Visit original content creator repository https://github.com/kaiosilveira/push-down-field-refactoring
  • cp-cli-automate-operations

    Deprecation Notice

    This public repository is read-only and no longer maintained.


    Automate Operations with CLI

    REUSE status

    Description

    This example script is a companion to the tutorial “Automate Account Operations with the Command Line Interface (CLI)”. For complete information, see the tutorial on developers.sap.com.

    With this example for the CLI for SAP BTP, you can automate the setting up of new development environments. This includes the creation of a directory, subaccounts and entitlements, as well as a Cloud Foundry space and an instance of the SAP HANA Cloud service in the space.

    Requirements

    You should have an account on SAP BTP.

    You need to have the cf CLI installed.

    Since the script is a bash shell script, an UNIX-like environment is required, such as macOS or Linux.

    Download and Installation

    After downloading, change the file extension to .sh.

    How to obtain support

    In the tutorial, you can use the option “Provide Feedback”.

    License

    Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the LICENSE file.

    Visit original content creator repository https://github.com/SAP-archive/cp-cli-automate-operations
  • sklearn-oblique-tree

    Visit original content creator repository
    https://github.com/Doctorado-ML/sklearn-oblique-tree

  • elections

    Scouts-Elections

    Introduction

    This static website is a program that lets our Scouts group create Elections to determine which leaders will be in our subgroups.

    As we don’t know how many kids will be there on Election day (absences…), this program allows for configurations on setup and when ready, shows the voting page with all the candidates entered on setup with a customizable number of votes. That voting page repeats until all the voters have went through.

    Since we don’t want to know who voted for who, there is no need to “register”, but we need to confirm if the kid really voted or not, and prevent him from voting more than once (which may skew the results).
    Therefore, after a voter’s vote, an overlay shows on the voting page, preventing any further actions until the special input is pressed, which will reset the page to allow for the next voter to actually vote.

    There is two way to trigger that special input :

    • When using a keyboard, you can use the current default keybinding of space
    • When having a touchscreen, you also have the ability to long press the top half portion of the overlay
      • This input is only available in the overlay that appears when someone voted, and can therefore not be triggered in the voting page

    Whenever that special input is used, a toast notification shows up for a brief moment showing how much voters remains, to keep track of the progress of the current voting session.

    That toast notification also has a button to skip remaining voters, in case you miscalculated the number of voters or simply want to skip the remaining ones.
    If skipped, the database will contain this information, which means that when loading this database the results will be shown right away (after entering the password, of course).

    There is also a way to spread the election between multiple devices to make that election go faster (multiple kids at the same time) : to learn more about this functionality, please scroll down to the relevant section.

    Setup page

    In the setup page, validations are used to prevent any bad inputs on setup (empty number of voters, empty candidate name, number of votes higher than the number of candidates (which doesn’t make sense, as every candidates would be voted for…), etc).

    The number of votes is setup to be a minimum and a maximum : you can give the voters between x and y votes, which allows them for example to vote between 3 to 5 candidates, or even between 0 and 5 candidates, which would mean they could skip their votes if desired.
    If there is the need to force a number of votes (for example, the voters need to vote 4 times), simply set the minimum and the maximum to the same number, and this case will be fulfilled.

    There is also a configuration option that allows the voters to vote multiple times for the same candidate : simply toggle it on or off (off by default).
    This toggle does not affect the number of votes logic described above.

    The name of the database is the name that will be given to the file if you want to download the database at the end.
    Validations rules on it prevents you from entering a filename that wouldn’t be accepted by Windows systems.

    Voting

    After setup, at any point, if the page gets reloaded or closed, the database will be downloaded in an unfinished state, allowing you to return to the state you were in.

    This allows some sort of protection in case a smart kid decides he wants to press Alt+F4 to mess up stuff.

    In the case you want to disable that, there is a checkbox in the setup page that is checked by default – simply uncheck it and the database won’t download automatically.
    Even with the automatic download disabled, you will still be able to download the database manually in the end if desired.

    As how does the voting process goes, a page gets shown before the actual votes to give a quick reminder to the scout leaders on how the voting process goes (as described below).

    The way it works is that all the candidates are shown with an input that is only available to the mouse (or touch) input which is configured based on the informations given at the setup page :

    If multiple votes is allowed per candidates, then an input that lets multiple votes on one candidate is used (with a plus and a minus button).
    Otherwise, a simple button is shown under each candidate that gives the possibility of voting for that candidate.
    Under the candidates cards stack rests a button to submit the votes : it is only enabled once the minimum number of votes (defined at setup!) was reached.
    This button also giggles a bit (when enabled) to let the kids know this button is clickable, to (hopefully) remind them that they need to press it.
    Above this buttton is a small text line showing how many votes are remaining for the current voter (or two lines if the minimum and the maximum are not the same).

    When the minimum number of votes was reached and the voter presses the submit button, an overlay shows up saying “Votes saved, thanks!”, which is a signal that the voter can now leave and do something else.
    Nothing on this page is clickable, so using the mouse is now useless in this overlay.
    This is where the scout leader comes into play : to go to the next voter, you press the space button on the keyboard and everything is reset in a state that lets another voter give its votes.
    On a device with a touch screen (i.e. : a phone), you can press the top half of the screen for a little time (about half a second should do it) and the same behavior will happen.
    Once no more voters is remaining, the results flow will kick in – you can follow the next section to learn more about it.

    Results

    Before showing results, a password is asked to prevent kids from viewing the results by accident.
    The password can be set in the setup page, and is optional : if you don’t set any password, when the last voter has finished voting, the overlay will show and going to the next voter will simply show the results directly.

    Please note that the password is not encrypted and is simply a bridge between the voters and the scout leaders.

    If you used this application before you could set the password (you probably didn’t 😉 ), and you try to load the database, the password still defaults to VL so you don’t get too lost.

    The results shown at the end are sorted by number of votes, meaning the most voted candidate will be on top and the lowest voted candidate will be at the bottom.

    The rows are clickable, which highlights the candidates (in a cycle of unselected, pre-selected and selected), allowing for discussions with other maintainers.

    The button to return to the homepage currently simply reloads the page, as this was an easier way of resetting the program’s state at the time. This behavior is something I want to change, which you can follow my progress in #43.

    Sharing elections between multiple devices

    The elections can be shared between multiple devices to allow for a single election to be spread across multiple devices.
    This is especially useful when there is alot of voters and the time to make everyone vote may be limited, since you can make multiple voters input their votes at the same time.

    To use this functionality, you simply need one device that creates the setup for the election, which would then use the dedicated Créer comme Élection Partagée button.
    A checkmark is shown next to this button to confirm if you have access to my server that makes this functionality possible.
    For more information about this server, please consult this page that explains why it is necessary.

    When the shared election is created, a code will be generated and shown on the creator’s screen, which you can now use on other devices to join the created election : you simply need to use the button to join this election on the home page, input the code that was shown on the creator’s screen (share it between yourselves however you want), and all the data will be fetched and the election will start as usual.

    Be aware that when voting, requests will be sent to the server to keep it up to date / in synchronization with other devices, so that you don’t vote 20 times on each device if you had 20 voters to begin with.
    When doing a request, a loading indicator will be shown to indicate that a request is occurring : the only exception for this is when a voter submits their vote(s), as they might be confused as to why there was something that appeared on screen for no apparent reason.

    The functionality to skip the remaining voters allows you to skip the election for everyone, not only the device that it was inputted on.
    A warning is shown when using this functionality in the shared election context, to let you truly decide the flow of your own shared election.
    If you skip the shared election, no new voters will be available to input their vote(s) : however, devices that already had a voter on it will still be able to send their vote(s).

    When no more “seats” are available (when every voter has voted or there are voter that are currenty voting), a page will be shown on devices that have no voters left that lets you know when there is no more voters remaining : it will verify automatically every 30 seconds, or you can manually verify yourself by pressing the button dedicated for it.
    This page allows you to bypass the remaining voters if that’s what you need (in case of issues, such has loss of Internet connectivity, for example) – this option however does not delete or skips the election, it simply shows the data that your device currently has.
    This page also allows you to send a request to delete the data on the server once the election is over.

    Finally, after 24 hours of inactivity (no one joins the shared election, send a vote request, fetches the results, etc), the data will be automatically deleted from my server.

    During the whole proceess, errors are handled and if you lose Internet connection, you will, most of the time, have the option to fallback to a local election instead.
    This option is there mostly to prevent your data from being lost, so that you can handle problems more easily.
    These errors are explained when they happen, and their text will be red to signal that it was an error.

    Miscellaneous

    All the text in here is in French, since our group is French-based.
    Code is in English because code should always be in English.

    Author

    • Guillaume Marcoux (V-ed) – Owner

    See also the list of contributors who participated in this project.

    License

    This project is licensed under the MIT License – see the LICENSE file for details

    Visit original content creator repository
    https://github.com/205stelzear/elections

  • Delizious-Ini

    Delizious Ini

    What?

    Delizious Ini is an easy to use .NET Standard library entirely written in C# for reading and writing of INI data
    that comes with an intuitive API design applying Domain-driven design (DDD).

    It provides extensive configurability and allows to specify failure behaviors (e.g. throw a specific exception in case a section or property does not exist, or proceed with a fallback behavior)
    for almost every operation on both instance and operation level.

    New features in version 1.21.0

    • Improve documentation of configurability summary in README

    Features

    Delizious Ini provides the following features:

    Upcoming features:

    • Merge two INI documents

    Getting started

    To install Delizious Ini, run the following command in the respective console:

    Package Manager Console

    PM> Install-Package Delizious.Ini
    

    .NET CLI Console

    > dotnet add package Delizious.Ini
    

    Quick start

    const string ini = """
                       [Section]
                       Property=Current value
                       AnotherProperty=Another value
    
                       [EmptySection]
                       """;
    
    using var textReader = new StringReader(ini);
    
    // Use default configuration 
    var configuration = IniDocumentConfiguration.Default
                                                .WithCaseSensitivity(CaseSensitivity.CaseSensitive); // Treat section names and property keys as case-sensitive (by default, case-insensitive)
    
    var iniDocument = IniDocument.LoadFrom(textReader, configuration);
    
    // Read existing property
    var originalValue = iniDocument.ReadProperty("Section", "Property");
    Console.WriteLine($@"Original property value: {originalValue}");
    
    // Update existing property
    iniDocument.WriteProperty("Section", "Property", "This is the new value");
    
    var updatedValue = iniDocument.ReadProperty("Section", "Property");
    Console.WriteLine($@"Updated property value: {updatedValue}");
    
    // Write new property
    iniDocument.WriteProperty("NewSection", "NewProperty", "NewValue");
    
    // Delete section
    iniDocument.DeleteSection("EmptySection");
    
    // Delete property
    iniDocument.DeleteProperty("Section", "AnotherProperty");
    
    Console.WriteLine();
    Console.WriteLine(@"INI document:");
    iniDocument.SaveTo(Console.Out);

    Examples

    Configure default behavior of an INI document

    // This configuration represents the loose configuration which is also predefined:
    //var looseConfiguration = IniDocumentConfiguration.Loose;
    var looseConfiguration =
        IniDocumentConfiguration.Default
                                .WithCaseSensitivity(CaseSensitivity.CaseInsensitive)                 // Treat section names and property keys as case-insensitive
                                .WithNewlineString(NewlineString.Environment)                         // Use newline string as given by current environment
                                .WithSectionBeginningDelimiter(SectionBeginningDelimiter.Default)     // Use default section beginning delimiter which is opening square bracket '['
                                .WithSectionEndDelimiter(SectionEndDelimiter.Default)                 // Use default section end delimiter which is closing square bracket ']'
                                .WithSectionNameRegex(SectionNameRegex.Default)                       // Use default section name regex which is '[\p{L}\p{M}\p{N}\p{P}\p{S}\p{Zs}]+'
                                .WithDuplicatePropertyBehavior(DuplicatePropertyBehavior.Ignore)      // Ignore subsequent occurrences of a duplicate property by using the first occurrence of such a property
                                .WithDuplicateSectionBehavior(DuplicateSectionBehavior.Merge)         // Merge a duplicate section
                                .WithInvalidLineBehavior(InvalidLineBehavior.Ignore)                  // Ignore when a line is invalid and cannot be parsed on loading
                                .WithPropertyAssignmentSeparator(PropertyAssignmentSeparator.Default) // Use default property assignment separator which is equality sign '='
                                .WithPropertyAssignmentSpacer(PropertyAssignmentSpacer.None)          // Use no property assignment spacer
                                .WithPropertyEnumerationMode(PropertyEnumerationMode.Fallback)        // Fallback to empty collection of property keys when section does not exist
                                .WithPropertyReadMode(PropertyReadMode.Fallback)                      // Fallback to empty string when property to read does not exist
                                .WithPropertyWriteMode(PropertyWriteMode.Create)                      // Create a new property or update an existing property
                                .WithPropertyDeletionMode(PropertyDeletionMode.Ignore)                // Ignore when property to delete does not exist
                                .WithSectionDeletionMode(SectionDeletionMode.Ignore)                  // Ignore when section to delete does not exist
                                .WithCommentString(CommentString.Default)                             // Use default comment string that indicates the beginning of a comment line which is a semicolon ';'
                                .WithCommentReadMode(CommentReadMode.Fallback)                        // Fallback to none comment when section or property to read comment does not exist
                                .WithCommentWriteMode(CommentWriteMode.Ignore);                       // Ignore when section or property to write the comment does not exist
    
    // This configuration represents the strict configuration which is also predefined:
    //var strictConfiguration = IniDocumentConfiguration.Strict;
    var strictConfiguration =
        IniDocumentConfiguration.Default
                                .WithCaseSensitivity(CaseSensitivity.CaseInsensitive)                 // Treat section names and property keys as case-insensitive
                                .WithNewlineString(NewlineString.Environment)                         // Use newline string as given by current environment
                                .WithSectionBeginningDelimiter(SectionBeginningDelimiter.Default)     // Use default section beginning delimiter which is opening square bracket '['
                                .WithSectionEndDelimiter(SectionEndDelimiter.Default)                 // Use default section end delimiter which is closing square bracket ']'
                                .WithSectionNameRegex(SectionNameRegex.Default)                       // Use default section name regex which is '[\p{L}\p{M}\p{N}\p{P}\p{S}\p{Zs}]+'
                                .WithDuplicatePropertyBehavior(DuplicatePropertyBehavior.Fail)        // Throw exception when a duplicate property occurs
                                .WithDuplicateSectionBehavior(DuplicateSectionBehavior.Fail)          // Throw exception when a duplicate section occurs
                                .WithInvalidLineBehavior(InvalidLineBehavior.Fail)                    // Throw exception when a line is invalid and cannot be parsed on loading
                                .WithPropertyAssignmentSeparator(PropertyAssignmentSeparator.Default) // Use default property assignment separator which is equality sign '='
                                .WithPropertyAssignmentSpacer(PropertyAssignmentSpacer.None)          // Use no property assignment spacer
                                .WithPropertyEnumerationMode(PropertyEnumerationMode.Fail)            // Throw exception when section to enumerate properties does not exist
                                .WithPropertyReadMode(PropertyReadMode.Fail)                          // Throw exception when property to read to does not exist
                                .WithPropertyWriteMode(PropertyWriteMode.Update)                      // Update existing property only but throw exception when property to write does not exist
                                .WithPropertyDeletionMode(PropertyDeletionMode.Fail)                  // Throw exception when property to delete does not exist
                                .WithSectionDeletionMode(SectionDeletionMode.Fail)                    // Throw exception when section to delete does not exist
                                .WithCommentString(CommentString.Default)                             // Use default comment string that indicates the beginning of a comment line which is a semicolon ';'
                                .WithCommentReadMode(CommentReadMode.Fail)                            // Throw exception when section or property to read comment does not exist
                                .WithCommentWriteMode(CommentWriteMode.Fail);                         // Throw exception when section or property to write the comment does not exist

    Load and save

    const string ini = """
                       [Section]
                       Property=Current value
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    // Save entire INI document to text writer by using Console.Out to output content
    var textWriter = Console.Out;
    iniDocument.SaveTo(textWriter);

    Enumeration of sections

    const string ini = """
                       [Section]
                       Property=Current value
    
                       [EmptySection]
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    foreach (var sectionName in iniDocument.EnumerateSections())
    {
        Console.WriteLine(sectionName);
    }

    Enumeration of properties

    const string ini = """
                       [Section]
                       Property=Current value
                       AnotherProperty=Another value
                       EmptyProperty=
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    foreach (var propertyName in iniDocument.EnumerateProperties("Section"))
    {
        Console.WriteLine(propertyName);
    }

    The enumeration of properties supports the following modes:

    Mode Description
    PropertyEnumerationMode.Fail Throw a SectionNotFoundException when the section does not exist.
    PropertyEnumerationMode.Fallback Fall back to an empty collection of properties when the section does not exist.

    Reading of a property

    The reading of a property supports the following modes:

    Mode Description
    PropertyReadMode.Fail Throw a SectionNotFoundException when the section does not exist, or throw a PropertyNotFoundException when the section exists but the property does not exist.
    PropertyReadMode.Fallback Fall back to PropertyValue.None if the section or property does not exist.
    PropertyReadMode.CustomFallback Fall back to the given custom property value if the section or property does not exist.

    Writing of a property

    The writing of a property supports the following modes:

    Mode Description
    PropertyWriteMode.Create Create a new property. If the property already exists, it will be overwritten. If the section does not exist, a new section is created. If the section exists but the property itself does not exist, a new property is created.
    PropertyWriteMode.Update Update an existing property and require that both the section and property exist. Throw a SectionNotFoundException when the section does not exist, or throw a PropertyNotFoundException when the section exists but the property does not exist.

    Deletion of a section

    const string ini = """
                       [Section]
                       Property=Current value
    
                       [EmptySection]
    
                       [AnotherSection]
                       AnotherProperty=With another value
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    iniDocument.DeleteSection("EmptySection");
    
    iniDocument.SaveTo(Console.Out);

    The deletion of a section supports the following modes:

    Mode Description
    SectionDeletionMode.Fail Throw a SectionNotFoundException when the section does not exist.
    SectionDeletionMode.Ignore Silently ignore if the section does not exist.

    Deletion of a property

    const string ini = """
                       [Section]
                       Property=Current value
                       AnotherProperty=Another value
                       EmptyProperty=
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    iniDocument.DeleteProperty("Section", "Property");
    
    iniDocument.SaveTo(Console.Out);

    The deletion of a property supports the following modes:

    Mode Description
    PropertyDeletionMode.Fail Throw a SectionNotFoundException when the section does not exist, or throw a PropertyNotFoundException when the section exists but the property does not exist.
    PropertyDeletionMode.Ignore Silently ignore if the section or the property does not exist.

    Reading the comment of a section

    const string ini = """
                       ;This is a sample
                       ;multiline
                       ;comment. :)
                       [Section]
                       Property=Value
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    var comment = iniDocument.ReadComment("Section");
    
    Console.WriteLine(comment);

    Reading the comment of a section supports the following modes:

    Mode Description
    CommentReadMode.Fail Throw a SectionNotFoundException when the section does not exist.
    CommentReadMode.Fallback Fall back to none comment if the section does not exist.
    CommentReadMode.CustomFallback Fall back to a custom fallback comment if the section does not exist.

    Reading the comment of a property

    const string ini = """
                       [Section]
                       ;This is a sample
                       ;multiline
                       ;comment. :)
                       Property=Value
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    var comment = iniDocument.ReadComment("Section", "Property");
    
    Console.WriteLine(comment);

    Reading the comment of a property supports the following modes:

    Mode Description
    CommentReadMode.Fail Throw a SectionNotFoundException when the section does not exist, or throw a PropertyNotFoundException when the section exists but the property does not exist.
    CommentReadMode.Fallback Fall back to none comment if the section or property does not exist.
    CommentReadMode.CustomFallback Fall back to a custom fallback comment if the section or property does not exist.

    Writing the comment of a section

    const string ini = """
                       [Section]
                       Property=Value
                       """;
    
    const string comment = """
                           This is a sample
                           multiline
                           comment. :)
                           """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    iniDocument.WriteComment("Section", comment);
    
    using var textWriter = new StringWriter();
    iniDocument.SaveTo(textWriter);
    
    textWriter.Flush();
    
    Console.WriteLine(textWriter);

    Writing the comment of a section supports the following modes:

    Mode Description
    CommentWriteMode.Fail Throw a SectionNotFoundException when the section does not exist.
    CommentWriteMode.Ignore Silently ignore if the section does not exist.

    Writing the comment of a property

    const string ini = """
                       [Section]
                       Property=Value
                       """;
    
    const string comment = """
                           This is a sample
                           multiline
                           comment. :)
                           """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    iniDocument.WriteComment("Section", "Property", comment);
    
    using var textWriter = new StringWriter();
    iniDocument.SaveTo(textWriter);
    
    textWriter.Flush();
    
    Console.WriteLine(textWriter);

    Writing the comment of a property supports the following modes:

    Mode Description
    CommentWriteMode.Fail Throw a SectionNotFoundException when the section does not exist, or throw a PropertyNotFoundException when the section exists but the property does not exist.
    CommentWriteMode.Ignore Silently ignore if the section or the property does not exist.

    License

    MIT License

    https://opensource.org/license/mit

    Socialize

    If you like or use my work and you are interested in this kind of software development let’s get in touch. 🙂

    Visit original content creator repository
    https://github.com/oliverzick/Delizious-Ini

  • Delizious-Ini

    Delizious Ini

    What?

    Delizious Ini is an easy to use .NET Standard library entirely written in C# for reading and writing of INI data
    that comes with an intuitive API design applying Domain-driven design (DDD).

    It provides extensive configurability and allows to specify failure behaviors (e.g. throw a specific exception in case a section or property does not exist, or proceed with a fallback behavior)
    for almost every operation on both instance and operation level.

    New features in version 1.21.0

    • Improve documentation of configurability summary in README

    Features

    Delizious Ini provides the following features:

    Upcoming features:

    • Merge two INI documents

    Getting started

    To install Delizious Ini, run the following command in the respective console:

    Package Manager Console

    PM> Install-Package Delizious.Ini
    

    .NET CLI Console

    > dotnet add package Delizious.Ini
    

    Quick start

    const string ini = """
                       [Section]
                       Property=Current value
                       AnotherProperty=Another value
    
                       [EmptySection]
                       """;
    
    using var textReader = new StringReader(ini);
    
    // Use default configuration 
    var configuration = IniDocumentConfiguration.Default
                                                .WithCaseSensitivity(CaseSensitivity.CaseSensitive); // Treat section names and property keys as case-sensitive (by default, case-insensitive)
    
    var iniDocument = IniDocument.LoadFrom(textReader, configuration);
    
    // Read existing property
    var originalValue = iniDocument.ReadProperty("Section", "Property");
    Console.WriteLine($@"Original property value: {originalValue}");
    
    // Update existing property
    iniDocument.WriteProperty("Section", "Property", "This is the new value");
    
    var updatedValue = iniDocument.ReadProperty("Section", "Property");
    Console.WriteLine($@"Updated property value: {updatedValue}");
    
    // Write new property
    iniDocument.WriteProperty("NewSection", "NewProperty", "NewValue");
    
    // Delete section
    iniDocument.DeleteSection("EmptySection");
    
    // Delete property
    iniDocument.DeleteProperty("Section", "AnotherProperty");
    
    Console.WriteLine();
    Console.WriteLine(@"INI document:");
    iniDocument.SaveTo(Console.Out);

    Examples

    Configure default behavior of an INI document

    // This configuration represents the loose configuration which is also predefined:
    //var looseConfiguration = IniDocumentConfiguration.Loose;
    var looseConfiguration =
        IniDocumentConfiguration.Default
                                .WithCaseSensitivity(CaseSensitivity.CaseInsensitive)                 // Treat section names and property keys as case-insensitive
                                .WithNewlineString(NewlineString.Environment)                         // Use newline string as given by current environment
                                .WithSectionBeginningDelimiter(SectionBeginningDelimiter.Default)     // Use default section beginning delimiter which is opening square bracket '['
                                .WithSectionEndDelimiter(SectionEndDelimiter.Default)                 // Use default section end delimiter which is closing square bracket ']'
                                .WithSectionNameRegex(SectionNameRegex.Default)                       // Use default section name regex which is '[\p{L}\p{M}\p{N}\p{P}\p{S}\p{Zs}]+'
                                .WithDuplicatePropertyBehavior(DuplicatePropertyBehavior.Ignore)      // Ignore subsequent occurrences of a duplicate property by using the first occurrence of such a property
                                .WithDuplicateSectionBehavior(DuplicateSectionBehavior.Merge)         // Merge a duplicate section
                                .WithInvalidLineBehavior(InvalidLineBehavior.Ignore)                  // Ignore when a line is invalid and cannot be parsed on loading
                                .WithPropertyAssignmentSeparator(PropertyAssignmentSeparator.Default) // Use default property assignment separator which is equality sign '='
                                .WithPropertyAssignmentSpacer(PropertyAssignmentSpacer.None)          // Use no property assignment spacer
                                .WithPropertyEnumerationMode(PropertyEnumerationMode.Fallback)        // Fallback to empty collection of property keys when section does not exist
                                .WithPropertyReadMode(PropertyReadMode.Fallback)                      // Fallback to empty string when property to read does not exist
                                .WithPropertyWriteMode(PropertyWriteMode.Create)                      // Create a new property or update an existing property
                                .WithPropertyDeletionMode(PropertyDeletionMode.Ignore)                // Ignore when property to delete does not exist
                                .WithSectionDeletionMode(SectionDeletionMode.Ignore)                  // Ignore when section to delete does not exist
                                .WithCommentString(CommentString.Default)                             // Use default comment string that indicates the beginning of a comment line which is a semicolon ';'
                                .WithCommentReadMode(CommentReadMode.Fallback)                        // Fallback to none comment when section or property to read comment does not exist
                                .WithCommentWriteMode(CommentWriteMode.Ignore);                       // Ignore when section or property to write the comment does not exist
    
    // This configuration represents the strict configuration which is also predefined:
    //var strictConfiguration = IniDocumentConfiguration.Strict;
    var strictConfiguration =
        IniDocumentConfiguration.Default
                                .WithCaseSensitivity(CaseSensitivity.CaseInsensitive)                 // Treat section names and property keys as case-insensitive
                                .WithNewlineString(NewlineString.Environment)                         // Use newline string as given by current environment
                                .WithSectionBeginningDelimiter(SectionBeginningDelimiter.Default)     // Use default section beginning delimiter which is opening square bracket '['
                                .WithSectionEndDelimiter(SectionEndDelimiter.Default)                 // Use default section end delimiter which is closing square bracket ']'
                                .WithSectionNameRegex(SectionNameRegex.Default)                       // Use default section name regex which is '[\p{L}\p{M}\p{N}\p{P}\p{S}\p{Zs}]+'
                                .WithDuplicatePropertyBehavior(DuplicatePropertyBehavior.Fail)        // Throw exception when a duplicate property occurs
                                .WithDuplicateSectionBehavior(DuplicateSectionBehavior.Fail)          // Throw exception when a duplicate section occurs
                                .WithInvalidLineBehavior(InvalidLineBehavior.Fail)                    // Throw exception when a line is invalid and cannot be parsed on loading
                                .WithPropertyAssignmentSeparator(PropertyAssignmentSeparator.Default) // Use default property assignment separator which is equality sign '='
                                .WithPropertyAssignmentSpacer(PropertyAssignmentSpacer.None)          // Use no property assignment spacer
                                .WithPropertyEnumerationMode(PropertyEnumerationMode.Fail)            // Throw exception when section to enumerate properties does not exist
                                .WithPropertyReadMode(PropertyReadMode.Fail)                          // Throw exception when property to read to does not exist
                                .WithPropertyWriteMode(PropertyWriteMode.Update)                      // Update existing property only but throw exception when property to write does not exist
                                .WithPropertyDeletionMode(PropertyDeletionMode.Fail)                  // Throw exception when property to delete does not exist
                                .WithSectionDeletionMode(SectionDeletionMode.Fail)                    // Throw exception when section to delete does not exist
                                .WithCommentString(CommentString.Default)                             // Use default comment string that indicates the beginning of a comment line which is a semicolon ';'
                                .WithCommentReadMode(CommentReadMode.Fail)                            // Throw exception when section or property to read comment does not exist
                                .WithCommentWriteMode(CommentWriteMode.Fail);                         // Throw exception when section or property to write the comment does not exist

    Load and save

    const string ini = """
                       [Section]
                       Property=Current value
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    // Save entire INI document to text writer by using Console.Out to output content
    var textWriter = Console.Out;
    iniDocument.SaveTo(textWriter);

    Enumeration of sections

    const string ini = """
                       [Section]
                       Property=Current value
    
                       [EmptySection]
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    foreach (var sectionName in iniDocument.EnumerateSections())
    {
        Console.WriteLine(sectionName);
    }

    Enumeration of properties

    const string ini = """
                       [Section]
                       Property=Current value
                       AnotherProperty=Another value
                       EmptyProperty=
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    foreach (var propertyName in iniDocument.EnumerateProperties("Section"))
    {
        Console.WriteLine(propertyName);
    }

    The enumeration of properties supports the following modes:

    Mode Description
    PropertyEnumerationMode.Fail Throw a SectionNotFoundException when the section does not exist.
    PropertyEnumerationMode.Fallback Fall back to an empty collection of properties when the section does not exist.

    Reading of a property

    The reading of a property supports the following modes:

    Mode Description
    PropertyReadMode.Fail Throw a SectionNotFoundException when the section does not exist, or throw a PropertyNotFoundException when the section exists but the property does not exist.
    PropertyReadMode.Fallback Fall back to PropertyValue.None if the section or property does not exist.
    PropertyReadMode.CustomFallback Fall back to the given custom property value if the section or property does not exist.

    Writing of a property

    The writing of a property supports the following modes:

    Mode Description
    PropertyWriteMode.Create Create a new property. If the property already exists, it will be overwritten. If the section does not exist, a new section is created. If the section exists but the property itself does not exist, a new property is created.
    PropertyWriteMode.Update Update an existing property and require that both the section and property exist. Throw a SectionNotFoundException when the section does not exist, or throw a PropertyNotFoundException when the section exists but the property does not exist.

    Deletion of a section

    const string ini = """
                       [Section]
                       Property=Current value
    
                       [EmptySection]
    
                       [AnotherSection]
                       AnotherProperty=With another value
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    iniDocument.DeleteSection("EmptySection");
    
    iniDocument.SaveTo(Console.Out);

    The deletion of a section supports the following modes:

    Mode Description
    SectionDeletionMode.Fail Throw a SectionNotFoundException when the section does not exist.
    SectionDeletionMode.Ignore Silently ignore if the section does not exist.

    Deletion of a property

    const string ini = """
                       [Section]
                       Property=Current value
                       AnotherProperty=Another value
                       EmptyProperty=
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    iniDocument.DeleteProperty("Section", "Property");
    
    iniDocument.SaveTo(Console.Out);

    The deletion of a property supports the following modes:

    Mode Description
    PropertyDeletionMode.Fail Throw a SectionNotFoundException when the section does not exist, or throw a PropertyNotFoundException when the section exists but the property does not exist.
    PropertyDeletionMode.Ignore Silently ignore if the section or the property does not exist.

    Reading the comment of a section

    const string ini = """
                       ;This is a sample
                       ;multiline
                       ;comment. :)
                       [Section]
                       Property=Value
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    var comment = iniDocument.ReadComment("Section");
    
    Console.WriteLine(comment);

    Reading the comment of a section supports the following modes:

    Mode Description
    CommentReadMode.Fail Throw a SectionNotFoundException when the section does not exist.
    CommentReadMode.Fallback Fall back to none comment if the section does not exist.
    CommentReadMode.CustomFallback Fall back to a custom fallback comment if the section does not exist.

    Reading the comment of a property

    const string ini = """
                       [Section]
                       ;This is a sample
                       ;multiline
                       ;comment. :)
                       Property=Value
                       """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    var comment = iniDocument.ReadComment("Section", "Property");
    
    Console.WriteLine(comment);

    Reading the comment of a property supports the following modes:

    Mode Description
    CommentReadMode.Fail Throw a SectionNotFoundException when the section does not exist, or throw a PropertyNotFoundException when the section exists but the property does not exist.
    CommentReadMode.Fallback Fall back to none comment if the section or property does not exist.
    CommentReadMode.CustomFallback Fall back to a custom fallback comment if the section or property does not exist.

    Writing the comment of a section

    const string ini = """
                       [Section]
                       Property=Value
                       """;
    
    const string comment = """
                           This is a sample
                           multiline
                           comment. :)
                           """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    iniDocument.WriteComment("Section", comment);
    
    using var textWriter = new StringWriter();
    iniDocument.SaveTo(textWriter);
    
    textWriter.Flush();
    
    Console.WriteLine(textWriter);

    Writing the comment of a section supports the following modes:

    Mode Description
    CommentWriteMode.Fail Throw a SectionNotFoundException when the section does not exist.
    CommentWriteMode.Ignore Silently ignore if the section does not exist.

    Writing the comment of a property

    const string ini = """
                       [Section]
                       Property=Value
                       """;
    
    const string comment = """
                           This is a sample
                           multiline
                           comment. :)
                           """;
    
    using var textReader = new StringReader(ini);
    var iniDocument = IniDocument.LoadFrom(textReader, IniDocumentConfiguration.Default);
    
    iniDocument.WriteComment("Section", "Property", comment);
    
    using var textWriter = new StringWriter();
    iniDocument.SaveTo(textWriter);
    
    textWriter.Flush();
    
    Console.WriteLine(textWriter);

    Writing the comment of a property supports the following modes:

    Mode Description
    CommentWriteMode.Fail Throw a SectionNotFoundException when the section does not exist, or throw a PropertyNotFoundException when the section exists but the property does not exist.
    CommentWriteMode.Ignore Silently ignore if the section or the property does not exist.

    License

    MIT License

    https://opensource.org/license/mit

    Socialize

    If you like or use my work and you are interested in this kind of software development let’s get in touch. 🙂

    Visit original content creator repository
    https://github.com/oliverzick/Delizious-Ini

  • jsil-ydnbp

    You Don’t Need A Boilerpalate

    Webpack configuration for you own custom boilerplate

    git clone && npm i && npm start

    The talk

    https://youtu.be/dfPCFTEbtKI

    Slides

    https://bit.ly/2xpZOEg

    Adding babel to transpile to es5

    If we want our code to transpile to es5 for cross-browser suport we need to add babel-core and babel-loader.
    Also it is best to add the babel-preset-env to have support for stage 4 proposals.

    $ npm i babel-core babel-loader babel-preset-env --save-dev

    In .babelrc:

    {
      "presets": ["env"]
    }

    In webpack.config:

    const { resolve } = require('path');
    
    module.exports = {
      module: {
        rules: [
          {
            test: /.js$/,
            loader: 'babel-loader'
            include: resolve(__dirname, 'src')
          }
        ]
      }
    }

    Transpile async await

    We need to add the babel-polyfill to our main entry point:

    $ npm i babel-polyfill --save-dev

    In webpack.config:

    module.exports = {
      entry: {
        main: ['babel-polyfill', './src']
      }
    }

    Tree Shaking

    In .babelrc, turn off preset’s module system:

    {
      "presets": [
        ["env", {"modules": false"}]
      ]
    }

    Dynamic imports

    For dynamic imports to work together with babel, babel needs to understand the import() sytanx.
    We need a plugin for it:

    $ npm i babel-plugin-syntax-dynamic-import --save-dev

    In .babelrc:

    {
      "presets": [
        ["env", {"modules": false}]
      ],
    
      "plugins": ["syntax-dynamic-import"]
    }

    Vendors chunk

    Create vendors chunk for third-party libreries.

    In webpack.config:

    module.exports = {
      entry: {
        main: './src',
        vendors: ['jquery', 'react', 'angular', 'lodash']
      },
      
      optimization: {
        splitChunks: {
          cacheGroups: {
            vendors: {
              chunks: 'initial',
                name: 'vendors',
                test: 'vendors',
                enforce: true
            },
          }
        }
      }
    
    }

    Visit original content creator repository
    https://github.com/alonronin/jsil-ydnbp

  • test-frame

    TestFrame v0.1.0

    The objective is just to provide a minimalist and simple frame to validate a HTTP/S API like REST based or GraphQL based API.

    It should stay explicit, easy to use and to customize.

    Deps

    You may have to dispose of Python because of “commander” package, will disapear.

    {
      "axios": "^0.19.2",
      "colors": "^1.4.0",
      "commander": "^5.1.0",
      "sleep": "^6.2.0"
    }

    Usage

    Install this package and include it into any js file :

    const ApiTest = require('../../index');
    
    // Package come with a Check module that has predefined functions to check common types.
    const Check = ApiTest.check;
    
    // Send GET message to /hello and check the returned value is a string and strictly 'hello'.
    ApiTest.get(
      '/hello'
      , (v) =>
          Check.typ.string(v)
          && v === 'hello'
      , 'Get hello message from server'
      , 'STANDARD API'
    );
    
    // You can define custom common functions by overriding Check ones.
    Check.success = v => !!v['result'] && v.result === 'success';
    
    // Send POST message with { name: 'foo_0' } payload and check return according Check.success.
    ApiTest.post(
        `/post/user`
        , { name: 'foo_0' }
        , (v) => Check.success(v)
        , `Post foo_0 user`
        , 'USER API MANAGEMENT'
    );
    
    
    // Send POST message with a bad payload and check that it does lead to a managed error.
    Check.error = v => !!v['result'] && v.result === 'failed';
    ApiTest.post(
        `/post/user`
        , { bad_value: 'bad_content' }
        , (v) => Check.error(v)
        , `Post a bad payload to add user`
        , 'USER API MANAGEMENT'
    );
    
    // You have access to 'testFor' function calling the s => { ... } function for all [ 'foo_1', ... ] list elements.
    ApiTest.testFor(['foo_1', 'foo_2', 'foo_3'], s => {
      ApiTest.post(
        `/post/user`
        , { name: s }
        , (v) => Check.success(v)
        , `Post ${s} user`
        , 'USER API MANAGEMENT'
      );
    });
    
    // When every test is declared use ApiTest.run() function to run everything.
    ApiTest.run();

    Then run tests using node interpreter

    $ node tests/hello/hello.js --help
    
    Usage: hello [options] <url>
    
    Options:
      -ss, --selfSigned <bool>              Accept Self Signed Certificate
      -ucao, --useAuthorityOnly <bool>      Use only authority file
      -ca, --authority <path>               Path to certificate authority file
      -cert, --certificate <path>           Path to certificate file
      -pk, --privateKey <path>              Path to the associate private key file
      -up12, --usePkcs12 <bool>             Use P12 file
      -p12, --pkcs12 <path>                 Path to the associate P12 file
      -p12pw, --pkcs12Password <string>     Password associated with the P12 file
      -https, --useHttps <bool>             Should use HTTPS instead of HTTP
      -vr, --verboseResponse <bool>         Should print server responses
      -vr, --verboseError <bool>            Should print server errors responses
      -a, --await <[1; 360000] as integer>  Set an await time between requests
      -m, --matching <string>               Execute tests matching given string
      -pn, --productName <string>           Execute parametered product named tests
      -h, --help                            display help for command
    
    $ node tests/hello/hello.js http://127.0.0.1:4200/
    

    Visit original content creator repository
    https://github.com/aeghost/test-frame