├── .clang-format
├── .clang-tidy
├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── API.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── Makefile
├── README.md
├── bench
├── hello_async.bench.js
└── hello_object_async.bench.js
├── binding.gyp
├── blacklist.txt
├── cloudformation
└── ci.template.js
├── codecov.yml
├── common.gypi
├── docs
├── benchmarking.md
├── debugging-with-vs-code.md
├── extended-tour.md
├── image
│ ├── howtodebug1.png
│ ├── howtodebug2.png
│ └── howtodebug3.png
├── npm-and-package-lock.md
└── publishing-binaries.md
├── lib
└── index.js
├── mason-versions.ini
├── package-lock.json
├── package.json
├── scripts
├── clang-format.sh
├── clang-tidy.sh
├── coverage.sh
├── create_scheme.sh
├── generate_compile_commands.py
├── library.xcscheme
├── liftoff.sh
├── node.xcscheme
├── publish.sh
└── sanitize.sh
├── src
├── cpu_intensive_task.hpp
├── module.cpp
├── module_utils.hpp
├── object_async
│ ├── hello_async.cpp
│ └── hello_async.hpp
├── object_sync
│ ├── hello.cpp
│ └── hello.hpp
├── standalone
│ ├── hello.cpp
│ └── hello.hpp
├── standalone_async
│ ├── hello_async.cpp
│ └── hello_async.hpp
└── standalone_promise
│ ├── hello_promise.cpp
│ └── hello_promise.hpp
└── test
├── hello.test.js
├── hello_async.test.js
├── hello_object.test.js
├── hello_object_async.test.js
└── hello_promise.test.js
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | # Mapbox.Variant C/C+ style
3 | Language: Cpp
4 | AccessModifierOffset: -2
5 | AlignAfterOpenBracket: Align
6 | AlignConsecutiveAssignments: false
7 | AlignConsecutiveDeclarations: false
8 | AlignEscapedNewlinesLeft: false
9 | AlignOperands: true
10 | AlignTrailingComments: true
11 | AllowAllParametersOfDeclarationOnNextLine: true
12 | AllowShortBlocksOnASingleLine: false
13 | AllowShortCaseLabelsOnASingleLine: false
14 | AllowShortFunctionsOnASingleLine: All
15 | AllowShortIfStatementsOnASingleLine: true
16 | AllowShortLoopsOnASingleLine: true
17 | AlwaysBreakAfterDefinitionReturnType: None
18 | AlwaysBreakAfterReturnType: None
19 | AlwaysBreakBeforeMultilineStrings: false
20 | AlwaysBreakTemplateDeclarations: true
21 | BinPackArguments: true
22 | BinPackParameters: true
23 | BraceWrapping:
24 | AfterClass: true
25 | AfterControlStatement: true
26 | AfterEnum: true
27 | AfterFunction: true
28 | AfterNamespace: false
29 | AfterObjCDeclaration: true
30 | AfterStruct: true
31 | AfterUnion: true
32 | BeforeCatch: true
33 | BeforeElse: true
34 | IndentBraces: false
35 | BreakBeforeBinaryOperators: None
36 | BreakBeforeBraces: Custom
37 | BreakBeforeTernaryOperators: true
38 | BreakConstructorInitializersBeforeComma: false
39 | ColumnLimit: 0
40 | CommentPragmas: '^ IWYU pragma:'
41 | ConstructorInitializerAllOnOneLineOrOnePerLine: true
42 | ConstructorInitializerIndentWidth: 4
43 | ContinuationIndentWidth: 4
44 | Cpp11BracedListStyle: true
45 | DerivePointerAlignment: false
46 | DisableFormat: false
47 | ExperimentalAutoDetectBinPacking: false
48 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
49 | IncludeCategories:
50 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
51 | Priority: 2
52 | - Regex: '^(<|"(gtest|isl|json)/)'
53 | Priority: 3
54 | - Regex: '.*'
55 | Priority: 1
56 | IndentCaseLabels: false
57 | IndentWidth: 4
58 | IndentWrappedFunctionNames: false
59 | KeepEmptyLinesAtTheStartOfBlocks: true
60 | MacroBlockBegin: ''
61 | MacroBlockEnd: ''
62 | MaxEmptyLinesToKeep: 1
63 | NamespaceIndentation: None
64 | ObjCBlockIndentWidth: 2
65 | ObjCSpaceAfterProperty: false
66 | ObjCSpaceBeforeProtocolList: true
67 | PenaltyBreakBeforeFirstCallParameter: 19
68 | PenaltyBreakComment: 300
69 | PenaltyBreakFirstLessLess: 120
70 | PenaltyBreakString: 1000
71 | PenaltyExcessCharacter: 1000000
72 | PenaltyReturnTypeOnItsOwnLine: 60
73 | PointerAlignment: Left
74 | ReflowComments: true
75 | SortIncludes: false
76 | SpaceAfterCStyleCast: false
77 | SpaceBeforeAssignmentOperators: true
78 | SpaceBeforeParens: ControlStatements
79 | SpaceInEmptyParentheses: false
80 | SpacesBeforeTrailingComments: 1
81 | SpacesInAngles: false
82 | SpacesInContainerLiterals: true
83 | SpacesInCStyleCastParentheses: false
84 | SpacesInParentheses: false
85 | SpacesInSquareBrackets: false
86 | Standard: Cpp11
87 | TabWidth: 4
88 | UseTab: Never
--------------------------------------------------------------------------------
/.clang-tidy:
--------------------------------------------------------------------------------
1 | ---
2 | Checks: '*,-fuchsia-default-arguments*,-llvm-header-guard,-modernize-use-trailing-return-type,-misc-non-private-member-variables-in-classes,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers'
3 | WarningsAsErrors: '*'
4 | HeaderFilterRegex: '\/src\/'
5 | AnalyzeTemporaryDtors: false
6 | CheckOptions:
7 | - key: google-readability-braces-around-statements.ShortStatementLines
8 | value: '1'
9 | - key: google-readability-function-size.StatementThreshold
10 | value: '800'
11 | - key: google-readability-namespace-comments.ShortNamespaceLines
12 | value: '10'
13 | - key: google-readability-namespace-comments.SpacesBeforeComments
14 | value: '2'
15 | - key: modernize-loop-convert.MaxCopySize
16 | value: '16'
17 | - key: modernize-loop-convert.MinConfidence
18 | value: reasonable
19 | - key: modernize-loop-convert.NamingStyle
20 | value: CamelCase
21 | - key: modernize-pass-by-value.IncludeStyle
22 | value: llvm
23 | - key: modernize-replace-auto-ptr.IncludeStyle
24 | value: llvm
25 | - key: modernize-use-nullptr.NullMacros
26 | value: 'NULL'
27 | ...
28 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: mapbox/node-cpp-skel
2 | on:
3 | push:
4 | branches:
5 | - main
6 | pull_request:
7 | branches:
8 | - main
9 |
10 | jobs:
11 | test:
12 | runs-on: ubuntu-22.04
13 | permissions:
14 | id-token: write
15 | contents: read
16 |
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | buildtype: ['release', 'debug']
21 | node-version: ['10', '12', '13']
22 |
23 | steps:
24 | - uses: actions/checkout@v4
25 | - name: Install packages
26 | run: |
27 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test
28 | sudo apt update
29 | sudo apt-get install -y libstdc++-5-dev
30 |
31 | - uses: actions/setup-node@v4
32 | with:
33 | node-version: ${{ matrix.node-version }}
34 |
35 | - name: Install and setup
36 | run: |
37 | node -v
38 | which node
39 | clang++ -v
40 | which clang++
41 | make "${BUILDTYPE}"
42 |
43 | - name: Run tests
44 | run: |
45 | npm test
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib/binding
2 | node_modules
3 | build
4 | mason_packages
5 | .DS_Store
6 | *tgz
--------------------------------------------------------------------------------
/API.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### Table of Contents
4 |
5 | * [hello][1]
6 | * [Examples][2]
7 | * [helloAsync][3]
8 | * [Parameters][4]
9 | * [Examples][5]
10 | * [helloPromise][6]
11 | * [Parameters][7]
12 | * [Examples][8]
13 | * [HelloObject][9]
14 | * [Examples][10]
15 | * [hello][11]
16 | * [Examples][12]
17 | * [HelloObjectAsync][13]
18 | * [Examples][14]
19 | * [helloAsync][15]
20 | * [Parameters][16]
21 | * [Examples][17]
22 |
23 | ## hello
24 |
25 | This is a synchronous standalone function that logs a string.
26 |
27 | ### Examples
28 |
29 | ```javascript
30 | const { hello } = require('@mapbox/node-cpp-skel');
31 | const check = hello();
32 | console.log(check); // => "hello world"
33 | ```
34 |
35 | Returns **[string][18]**
36 |
37 | ## helloAsync
38 |
39 | This is an asynchronous standalone function that logs a string.
40 |
41 | ### Parameters
42 |
43 | * `args` **[Object][19]** different ways to alter the string
44 |
45 | * `args.louder` **[boolean][20]** adds exclamation points to the string
46 | * `args.buffer` **[boolean][20]** returns value as a node buffer rather than a string
47 | * `callback` **[Function][21]** from whence the hello comes, returns a string
48 |
49 | ### Examples
50 |
51 | ```javascript
52 | const { helloAsync } = require('@mapbox/node-cpp-skel');
53 | helloAsync({ louder: true }, function(err, result) {
54 | if (err) throw err;
55 | console.log(result); // => "...threads are busy async bees...hello
56 | world!!!!"
57 | });
58 | ```
59 |
60 | Returns **[string][18]**
61 |
62 | ## helloPromise
63 |
64 | This is a function that returns a promise. It multiplies a string N times.
65 |
66 | ### Parameters
67 |
68 | * `options` **[Object][19]?** different ways to alter the string
69 |
70 | * `options.phrase` **[string][18]** the string to multiply (optional, default `hello`)
71 | * `options.multiply` **[Number][22]** duplicate the string this number of times (optional, default `1`)
72 |
73 | ### Examples
74 |
75 | ```javascript
76 | const { helloPromise } = require('@mapbox/node-cpp-skel');
77 | const result = await helloAsync({ phrase: 'Howdy', multiply: 3 });
78 | console.log(result); // HowdyHowdyHowdy
79 | ```
80 |
81 | Returns **[Promise][23]**
82 |
83 | ## HelloObject
84 |
85 | Synchronous class, called HelloObject
86 |
87 | ### Examples
88 |
89 | ```javascript
90 | const { HelloObject } = require('@mapbox/node-cpp-skel');
91 | const Obj = new HelloObject('greg');
92 | ```
93 |
94 | ### hello
95 |
96 | Say hello
97 |
98 | #### Examples
99 |
100 | ```javascript
101 | const x = Obj.hello();
102 | console.log(x); // => '...initialized an object...hello greg'
103 | ```
104 |
105 | Returns **[String][18]**
106 |
107 | ## HelloObjectAsync
108 |
109 | Asynchronous class, called HelloObjectAsync
110 |
111 | ### Examples
112 |
113 | ```javascript
114 | const { HelloObjectAsync } = require('@mapbox/node-cpp-skel');
115 | const Obj = new module.HelloObjectAsync('greg');
116 | ```
117 |
118 | ### helloAsync
119 |
120 | Say hello while doing expensive work in threads
121 |
122 | #### Parameters
123 |
124 | * `args` **[Object][19]** different ways to alter the string
125 |
126 | * `args.louder` **[boolean][20]** adds exclamation points to the string
127 | * `args.buffer` **[buffer][24]** returns object as a node buffer rather then string
128 | * `callback` **[Function][21]** from whence the hello comes, returns a string
129 |
130 | #### Examples
131 |
132 | ```javascript
133 | const { HelloObjectAsync } = require('@mapbox/node-cpp-skel');
134 | const Obj = new HelloObjectAsync('greg');
135 | Obj.helloAsync({ louder: true }, function(err, result) {
136 | if (err) throw err;
137 | console.log(result); // => '...threads are busy async bees...hello greg!!!'
138 | });
139 | ```
140 |
141 | Returns **[String][18]**
142 |
143 | [1]: #hello
144 |
145 | [2]: #examples
146 |
147 | [3]: #helloasync
148 |
149 | [4]: #parameters
150 |
151 | [5]: #examples-1
152 |
153 | [6]: #hellopromise
154 |
155 | [7]: #parameters-1
156 |
157 | [8]: #examples-2
158 |
159 | [9]: #helloobject
160 |
161 | [10]: #examples-3
162 |
163 | [11]: #hello-1
164 |
165 | [12]: #examples-4
166 |
167 | [13]: #helloobjectasync
168 |
169 | [14]: #examples-5
170 |
171 | [15]: #helloasync-1
172 |
173 | [16]: #parameters-2
174 |
175 | [17]: #examples-6
176 |
177 | [18]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
178 |
179 | [19]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
180 |
181 | [20]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
182 |
183 | [21]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function
184 |
185 | [22]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
186 |
187 | [23]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
188 |
189 | [24]: https://nodejs.org/api/buffer.html
190 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 2/21/2022
2 |
3 | * Add `helloPromise` function example using [Napi::Promise](https://github.com/nodejs/node-addon-api/blob/c54aeef5fd37d3304e61af189672f9f61d403e6f/doc/promises.md)
4 | * Move all JSDoc to lib/index.js since versions >=5 do not support the `--polyglot` flag and give docs a little refresh
5 |
6 | # 1/9/2018
7 |
8 | * Add memory stats option to bench tests
9 |
10 | # 1/4/2018
11 |
12 | * Add doc note about remote vs local coverage using `LCOV`
13 |
14 | # 11/17/2017
15 |
16 | * Add liftoff script, setup docs, and more contributing details per https://github.com/mapbox/node-cpp-skel/pull/87
17 |
18 | # 10/31/2017
19 |
20 | * Add [sanitzer flag doc](https://github.com/mapbox/node-cpp-skel/pull/84)
21 | * Add [sanitizer script](hhttps://github.com/mapbox/node-cpp-skel/pull/85) and enable [leak sanitizer](https://github.com/mapbox/node-cpp-skel/commit/725601e4c7df6cb8477a128f018fb064a9f6f9aa)
22 | *
23 |
24 | # 10/20/2017
25 |
26 | * Add [code of conduct](https://github.com/mapbox/node-cpp-skel/pull/82)
27 | * Add [CC0 license](https://github.com/mapbox/node-cpp-skel/pull/82)
28 | * Point to [cpp glossary](https://github.com/mapbox/node-cpp-skel/pull/83)
29 |
30 | # 10/12/2017
31 |
32 | * Update compiler flags per best practices per https://github.com/mapbox/cpp/issues/37
33 | - https://github.com/mapbox/node-cpp-skel/pull/80
34 | - https://github.com/mapbox/node-cpp-skel/pull/78
35 | - https://github.com/mapbox/node-cpp-skel/pull/77
36 |
37 | # 09/10/2017
38 |
39 | * [Sanitize update](https://github.com/mapbox/node-cpp-skel/pull/74)
40 |
41 | # 08/24/2017
42 |
43 | * Clang tidy updates
44 | - https://github.com/mapbox/node-cpp-skel/pull/68
45 | - https://github.com/mapbox/node-cpp-skel/issues/65
46 | - https://github.com/mapbox/node-cpp-skel/pull/64
47 | - https://github.com/mapbox/node-cpp-skel/pull/66
48 |
49 | # 08/15/2017
50 |
51 | * Add [bench scripts](https://github.com/mapbox/node-cpp-skel/pull/61) for async examples
52 |
53 | # 08/09/2017
54 |
55 | * Add comments about "new" allocation
56 |
57 | # 08/08/2017
58 |
59 | * Add [clang-format](https://github.com/mapbox/node-cpp-skel/pull/56)
60 |
61 | # 08/04/2017
62 |
63 | * Use Nan's safer and high performance `Nan::Utf8String` when accepting string args per https://github.com/mapbox/node-cpp-skel/pull/55
64 |
65 | # 08/3/2017
66 |
67 | * Reorganize [documentation](https://github.com/mapbox/node-cpp-skel/pull/53)
68 |
69 | # 07/21/2017
70 |
71 | * Add [object_async example](https://github.com/mapbox/node-cpp-skel/pull/52)
72 |
73 | # 07/11/2017
74 |
75 | * Add [build docs](https://github.com/mapbox/node-cpp-skel/pull/51)
76 |
77 | * It begins
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of conduct
2 |
3 | Everyone is invited to participate in Mapbox’s open source projects and public discussions: we want to create a welcoming and friendly environment. Harassment of participants or other unethical and unprofessional behavior will not be tolerated in our spaces. The [Contributor Covenant](http://contributor-covenant.org) applies to all projects under the Mapbox organization and we ask that you please read [the full text](http://contributor-covenant.org/version/1/2/0/).
4 |
5 | You can learn more about our open source philosophy on [mapbox.com](https://www.mapbox.com/about/open/).
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thanks for getting involved and contributing to the skel :tada: Below are a few things to setup when submitting a PR.
4 |
5 | ## Code comments
6 |
7 | If adding new code, be sure to include relevant code comments. Code comments are a great way for others to learn from your code. This is especially true within the skeleton, since it is made for learning.
8 |
9 | ## Update Documentation
10 |
11 | Be sure to update any documentation relevant to your change. This includes updating the [CHANGELOG.md](https://github.com/mapbox/node-cpp-skel/blob/master/CHANGELOG.md).
12 |
13 | ## [Code Formatting](/docs/extended-tour.md#clang-tools)
14 |
15 | We use [this script](/scripts/clang-format.sh#L20) to install a consistent version of [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) to format the code base. The format is automatically checked via a Travis CI build as well. Run the following script locally to ensure formatting is ready to merge:
16 |
17 | make format
18 |
19 | We also use [`clang-tidy`](https://clang.llvm.org/extra/clang-tidy/) as a C++ linter. Run the following command to lint and ensure your code is ready to merge:
20 |
21 | make tidy
22 |
23 | These commands are set from within [the Makefile](./Makefile).
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 |
3 | Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an "owner") of an original work of
8 | authorship and/or a database (each, a "Work").
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific
12 | works ("Commons") that the public can reliably and without fear of later
13 | claims of infringement build upon, modify, incorporate in other works, reuse
14 | and redistribute as freely as possible in any form whatsoever and for any
15 | purposes, including without limitation commercial purposes. These owners may
16 | contribute to the Commons to promote the ideal of a free culture and the
17 | further production of creative, cultural and scientific works, or to gain
18 | reputation or greater distribution for their Work in part through the use and
19 | efforts of others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation
22 | of additional consideration or compensation, the person associating CC0 with a
23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25 | and publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights ("Copyright and
31 | Related Rights"). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 |
34 | i. the right to reproduce, adapt, distribute, perform, display, communicate,
35 | and translate a Work;
36 |
37 | ii. moral rights retained by the original author(s) and/or performer(s);
38 |
39 | iii. publicity and privacy rights pertaining to a person's image or likeness
40 | depicted in a Work;
41 |
42 | iv. rights protecting against unfair competition in regards to a Work,
43 | subject to the limitations in paragraph 4(a), below;
44 |
45 | v. rights protecting the extraction, dissemination, use and reuse of data in
46 | a Work;
47 |
48 | vi. database rights (such as those arising under Directive 96/9/EC of the
49 | European Parliament and of the Council of 11 March 1996 on the legal
50 | protection of databases, and under any national implementation thereof,
51 | including any amended or successor version of such directive); and
52 |
53 | vii. other similar, equivalent or corresponding rights throughout the world
54 | based on applicable law or treaty, and any national implementations thereof.
55 |
56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59 | and Related Rights and associated claims and causes of action, whether now
60 | known or unknown (including existing as well as future claims and causes of
61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
62 | duration provided by applicable law or treaty (including future time
63 | extensions), (iii) in any current or future medium and for any number of
64 | copies, and (iv) for any purpose whatsoever, including without limitation
65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66 | the Waiver for the benefit of each member of the public at large and to the
67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver
68 | shall not be subject to revocation, rescission, cancellation, termination, or
69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work
70 | by the public as contemplated by Affirmer's express Statement of Purpose.
71 |
72 | 3. Public License Fallback. Should any part of the Waiver for any reason be
73 | judged legally invalid or ineffective under applicable law, then the Waiver
74 | shall be preserved to the maximum extent permitted taking into account
75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76 | is so judged Affirmer hereby grants to each affected person a royalty-free,
77 | non transferable, non sublicensable, non exclusive, irrevocable and
78 | unconditional license to exercise Affirmer's Copyright and Related Rights in
79 | the Work (i) in all territories worldwide, (ii) for the maximum duration
80 | provided by applicable law or treaty (including future time extensions), (iii)
81 | in any current or future medium and for any number of copies, and (iv) for any
82 | purpose whatsoever, including without limitation commercial, advertising or
83 | promotional purposes (the "License"). The License shall be deemed effective as
84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the
85 | License for any reason be judged legally invalid or ineffective under
86 | applicable law, such partial invalidity or ineffectiveness shall not
87 | invalidate the remainder of the License, and in such case Affirmer hereby
88 | affirms that he or she will not (i) exercise any of his or her remaining
89 | Copyright and Related Rights in the Work or (ii) assert any associated claims
90 | and causes of action with respect to the Work, in either case contrary to
91 | Affirmer's express Statement of Purpose.
92 |
93 | 4. Limitations and Disclaimers.
94 |
95 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
96 | surrendered, licensed or otherwise affected by this document.
97 |
98 | b. Affirmer offers the Work as-is and makes no representations or warranties
99 | of any kind concerning the Work, express, implied, statutory or otherwise,
100 | including without limitation warranties of title, merchantability, fitness
101 | for a particular purpose, non infringement, or the absence of latent or
102 | other defects, accuracy, or the present or absence of errors, whether or not
103 | discoverable, all to the greatest extent permissible under applicable law.
104 |
105 | c. Affirmer disclaims responsibility for clearing rights of other persons
106 | that may apply to the Work or any use thereof, including without limitation
107 | any person's Copyright and Related Rights in the Work. Further, Affirmer
108 | disclaims responsibility for obtaining any necessary consents, permissions
109 | or other rights required for any use of the Work.
110 |
111 | d. Affirmer understands and acknowledges that Creative Commons is not a
112 | party to this document and has no duty or obligation with respect to this
113 | CC0 or use of the Work.
114 |
115 | For more information, please see
116 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # This Makefile serves a few purposes:
2 | #
3 | # 1. It provides an interface to iterate quickly while developing the C++ code in src/
4 | # by typing `make` or `make debug`. To make iteration as fast as possible it calls out
5 | # directly to underlying build tools and skips running steps that appear to have already
6 | # been run (determined by the presence of a known file or directory). What `make` does is
7 | # the same as running `npm install --build-from-source` except that it is faster when
8 | # run a second time because it will skip re-running expensive steps.
9 | # Note: in rare cases (like if you hit `crtl-c` during an install) you might end up with
10 | # build deps only partially installed. In this case you should run `make distclean` to fully
11 | # restore your repo to is starting state and then running `make` again should start from
12 | # scratch, fixing any inconsistencies.
13 | #
14 | # 2. It provides a few commands that call out to external scripts like `make coverage` or
15 | # `make tidy`. These scripts can be called directly but this Makefile provides a more uniform
16 | # interface to call them.
17 | #
18 | # To learn more about the build system see https://github.com/mapbox/node-cpp-skel/blob/master/docs/extended-tour.md#builds
19 |
20 | # Whether to turn compiler warnings into errors
21 | export WERROR ?= true
22 |
23 | # the default target. This line means that
24 | # just typing `make` will call `make release`
25 | default: release
26 |
27 | node_modules/node-addon-api:
28 | npm install --ignore-scripts
29 |
30 | mason_packages/headers: node_modules/node-addon-api
31 | node_modules/.bin/mason-js install
32 |
33 | mason_packages/.link/include: mason_packages/headers
34 | node_modules/.bin/mason-js link
35 |
36 | build-deps: mason_packages/.link/include
37 |
38 | release: build-deps
39 | V=1 ./node_modules/.bin/node-pre-gyp configure build --error_on_warnings=$(WERROR) --loglevel=error
40 | @echo "run 'make clean' for full rebuild"
41 |
42 | debug: mason_packages/.link/include
43 | V=1 ./node_modules/.bin/node-pre-gyp configure build --error_on_warnings=$(WERROR) --loglevel=error --debug
44 | @echo "run 'make clean' for full rebuild"
45 |
46 | coverage: build-deps
47 | ./scripts/coverage.sh
48 |
49 | tidy: build-deps
50 | ./scripts/clang-tidy.sh
51 |
52 | format: build-deps
53 | ./scripts/clang-format.sh
54 |
55 | sanitize: build-deps
56 | ./scripts/sanitize.sh
57 |
58 | clean:
59 | rm -rf lib/binding
60 | rm -rf build
61 | # remove remains from running 'make coverage'
62 | rm -f *.profraw
63 | rm -f *.profdata
64 | @echo "run 'make distclean' to also clear node_modules, mason_packages, and .mason directories"
65 |
66 | distclean: clean
67 | rm -rf node_modules
68 | rm -rf mason_packages
69 |
70 | # variable used in the `xcode` target below
71 | MODULE_NAME := $(shell node -e "console.log(require('./package.json').binary.module_name)")
72 |
73 | xcode: node_modules
74 | ./node_modules/.bin/node-pre-gyp configure -- -f xcode
75 | @# If you need more targets, e.g. to run other npm scripts, duplicate the last line and change NPM_ARGUMENT
76 | SCHEME_NAME="$(MODULE_NAME)" SCHEME_TYPE=library BLUEPRINT_NAME=$(MODULE_NAME) BUILDABLE_NAME=$(MODULE_NAME).node scripts/create_scheme.sh
77 | SCHEME_NAME="npm test" SCHEME_TYPE=node BLUEPRINT_NAME=$(MODULE_NAME) BUILDABLE_NAME=$(MODULE_NAME).node NODE_ARGUMENT="`npm bin tape`/tape test/*.test.js" scripts/create_scheme.sh
78 |
79 | open build/binding.xcodeproj
80 |
81 | testpack:
82 | rm -f ./*tgz
83 | npm pack
84 | tar -ztvf *tgz
85 |
86 | docs:
87 | npm run docs
88 |
89 | test:
90 | npm test
91 |
92 | .PHONY: test docs
93 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | [](https://travis-ci.com/mapbox/node-cpp-skel)
3 | [](https://codecov.io/gh/mapbox/node-cpp-skel)
4 |
5 | A skeleton for building a C++ addon for Node.js. This is a small, helper repository that generates simple `HelloWorld` Javascript example constructors. The examples have a number of methods to demonstrate different ways to use the Node C+ API for building particular types of functionality (i.e. asynchronous functions). Use this repo as both a template for your own code as well as a learning tool if you're just starting to develop Node/C++ Addons.
6 |
7 | **Why port C++ to Node.js?**. That's a great question! C++ is a high performance language that allows you to execute operations without clogging up the event loop. Node.js is single-threaded, which blocks execution. Even in highly optimized javascript code it may be impossible to improve performance. Passing heavy operations into C++ and subsequently into C++ workers can greatly improve the overall runtime of the code. Porting C++ code to Node.js is also referred to as creating an ["Addon"](https://github.com/mapbox/cpp/blob/master/node-cpp.md).
8 |
9 | More examples of how to port C++ libraries to node can be found at [nodejs.org/api/addons.html](https://nodejs.org/api/addons.html).
10 |
11 | # What's in the box? :package:
12 |
13 | This repository itself can be cloned and edited to your needs. The skeleton prepares a C++ port to Node.js and provides the following for quick development:
14 |
15 | * **Tests**: created with [Tape](https://github.com/substack/tape) in the `test/` directory. Travis CI file is prepared to build and test your project on every push.
16 | * **Documentation**: use this README as a template and customize for your own project. Also, this skeleton uses [documentation.js](http://documentation.js.org/) to generate API documentation from JSDOC comments in the `.cpp` files. Docs are located in `API.md`.
17 | * **[Benchmarking](./docs/benchmarking.md)**: Easily test the performance of your code using the built-in benchmark tests provided in this skeleton.
18 | * **Build system**: [node-pre-gyp](https://github.com/mapbox/node-pre-gyp) generates binaries with the proper system architecture flags
19 | * **[Publishing](./docs/publishing-binaries.md)**: Structured as a node module with a `package.json` that can be deployed to NPM's registry.
20 | * **Learning resources**: Read the detailed inline comments within the example code to learn exactly what is happening behind the scenes. Also, check out the [extended tour](./docs/extended-tour.md) to learn more about Node/C++ Addon development, builds, Xcode, and more details about the configuration of this skeleton.
21 |
22 | # Installation
23 |
24 | Each `make` command is specified in [`Makefile`](./Makefile)
25 |
26 | ```bash
27 | git clone git@github.com:mapbox/node-cpp-skel.git
28 | cd node-cpp-skel
29 |
30 | # Build binaries. This looks to see if there were changes in the C++ code. This does not reinstall deps.
31 | make
32 |
33 | # Run tests
34 | make test
35 |
36 | # Cleans your current builds and removes potential cache
37 | make clean
38 |
39 | # Build binaries in Debug mode (https://github.com/mapbox/cpp/blob/master/glossary.md#debug-build)
40 | make debug
41 |
42 | # Cleans everything, including the things you download from the network in order to compile (ex: npm packages).
43 | # This is useful if you want to nuke everything and start from scratch.
44 | # For example, it's super useful for making sure everything works for Travis, production, someone else's machine, etc
45 | make distclean
46 |
47 | # This skel uses documentation.js to auto-generate API docs.
48 | # If you'd like to generate docs for your code, you'll need to install documentation.js,
49 | # and then add your subdirectory to the docs command in package.json
50 | npm install -g documentation@4.0.0
51 | npm run docs
52 | ```
53 |
54 | NOTE: we are pinned to `documentation@4.0.0` because 5.x removed C++ support: https://github.com/documentationjs/documentation/blob/master/CHANGELOG.md#500-2017-07-27
55 |
56 | ### Customizing the compiler toolchain
57 |
58 | By default we use `clang++` via [mason](https://github.com/mapbox/mason). The reason we do this is:
59 |
60 | - We want to run the latest and greatest compiler version, to catch the most bugs, provide the best developer experience, and trigger the most helpful warnings
61 | - We use clang-format to format the code and each version of clang-format formats code slightly differently. To avoid friction around this (and ensure all devs format the code the same) we default to using the same version of clang++ via mason.
62 | - We want to support [LTO](https://github.com/mapbox/cpp/blob/master/glossary.md#link-time-optimization) in the builds, which is difficult to do on linux unless you control the toolchain tightly.
63 |
64 | The version of the clang++ binary (and related tools) is controlled by the [`mason-versions.ini`](./mason-versions.ini), and uses `mason-js` uses to install the toolchain.
65 |
66 | All that said, it is still absolutely possible and encouraged to compile your module with another compiler toolchain. In fact we hope that modules based on node-cpp-skel do this!
67 |
68 | To customize the toolchain you can override the defaults by setting these environment variables: CXX, CC, LINK, AR, NM. For example to use g++-6 you could do:
69 |
70 |
71 | ```bash
72 | export CXX="g++-6"
73 | export CC="gcc-6"
74 | export LINK="g++-6"
75 | export AR="ar"
76 | export NM="nm"
77 | make
78 | ```
79 |
80 | These environment variables will override the compiler toolchain defaults in `make_global_settings` in the [`binding.gyp`](./binding.gyp).
81 |
82 |
83 | ### Warnings as errors
84 |
85 | By default the build errors on compiler warnings. To disable this do:
86 |
87 | ```
88 | WERROR=false make
89 | ```
90 |
91 | ### Sanitizers
92 |
93 | You can run the [sanitizers](https://github.com/mapbox/cpp/blob/master/glossary.md#sanitizers), to catch additional bugs, by doing:
94 |
95 | ```shell
96 | make sanitize
97 | ```
98 |
99 | The sanitizers [are part of the compiler](https://github.com/mapbox/cpp/blob/master/glossary.md#sanitizers) and are also run in a specific job on Travis.
100 |
101 | # Add Custom Code
102 |
103 | Depending on your usecase, there are a variety of ways to start using this skeleton for your project.
104 |
105 | ### Setup new project
106 | Easily use this skeleton as a starting off point for a _new_ custom project:
107 |
108 | ```
109 | # Clone node-cpp-skel locally
110 |
111 | git clone git@github.com:mapbox/node-cpp-skel.git
112 | cd node-cpp-skel/
113 |
114 | # Create your new repo on GitHub and have the remote repo url handy for liftoff
115 | # Then run the liftoff script from within your local node-cpp-skel root directory.
116 | #
117 | # This will:
118 | # - prompt you for the new name of your project and the new remote repo url
119 | # - automatically create a new directory for your new project repo
120 | # - create a new branch called "node-cpp-skel-port" within your new repo directory
121 | # - add, commit, and push that branch to your new repo
122 |
123 | ./scripts/liftoff.sh
124 |
125 | ```
126 |
127 | ### Add your code
128 | Once your project has ported node-cpp-skel, follow these steps to integrate your own code:
129 |
130 | - Create a dir in `./src` to hold your custom code. See the example code within `/src` for reference.
131 | - Add your new method or class to `./src/module.cpp`, and `#include` it at the top
132 | - Add your new file-to-be-compiled to the list of target sources in `./binding.gyp`
133 | - Run `make` and see what surprises await on your new journey :boat:
134 |
135 | ### Adding dependencies
136 | With updated versions of npm, a `package-lock.json` file is created, which is now included in node-cpp-skel. See [`npm-and-package-lock.md`](./docs/npm-and-package-lock.md) for more info on how to interact with this file and how to add new dependencies.
137 |
138 | ### Interactive Debugging
139 |
140 | * [Debugging with VS Code](./docs/debugging-with-vs-code.md)
141 |
142 | # Code coverage
143 |
144 | Code coverage is critical for knowing how well your tests actually test all your code. To see code coverage you can view current results online at [](https://codecov.io/gh/mapbox/node-cpp-skel) or you can build in a customized way and display coverage locally like:
145 |
146 | ```
147 | make coverage
148 | ```
149 |
150 | **Note**
151 |
152 | Use [`// LCOV_EXCL_START` and `// LCOV_EXCL_STOP`](https://github.com/mapbox/vtvalidate/blob/master/src/vtvalidate.cpp#L70-L73) to ignore from [codecov](https://codecov.io/gh/mapbox/node-cpp-skel) _remotely_. However, this won't ignore when running coverage _locally_.
153 |
154 | For more details about what `make coverage` is doing under the hood see https://github.com/mapbox/cpp#code-coverage.
155 |
156 | # Contributing and License
157 |
158 | Contributors are welcome! :sparkles: This repo exists as a place to gather C++/Node Addon knowledge that will benefit the larger community. Please contribute your knowledge if you'd like.
159 |
160 | Node-cpp-skel is licensed under [CC0](https://creativecommons.org/share-your-work/public-domain/cc0/). Attribution is not required, but definitely welcome! If your project uses this skeleton, please add the node-cpp-skel badge to your readme so that others can learn about the resource.
161 |
162 | [](https://github.com/mapbox/node-cpp-skel)
163 |
164 | To include the badge, paste this into your README.md file:
165 | ```
166 | [](https://github.com/mapbox/node-cpp-skel)
167 | ```
168 |
169 | See [CONTRIBUTING](CONTRIBUTING.md) and [LICENSE](LICENSE.md) for more info.
170 |
--------------------------------------------------------------------------------
/bench/hello_async.bench.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var argv = require('minimist')(process.argv.slice(2));
4 | if (!argv.iterations || !argv.concurrency) {
5 | console.error('Please provide desired iterations, concurrency');
6 | console.error('Example: \n\tnode bench/hello_async.bench.js --iterations 50 --concurrency 10');
7 | console.error('Optional args: \n\t--mem (reports memory stats)');
8 | process.exit(1);
9 | }
10 |
11 | // This env var sets the libuv threadpool size.
12 | // This value is locked in once a function interacts with the threadpool
13 | // Therefore we need to set this value either in the shell or at the very
14 | // top of a JS file (like we do here)
15 | process.env.UV_THREADPOOL_SIZE = argv.concurrency;
16 |
17 | var fs = require('fs');
18 | var path = require('path');
19 | var bytes = require('bytes');
20 | var assert = require('assert')
21 | var d3_queue = require('d3-queue');
22 | var module = require('../lib/index.js');
23 | var queue = d3_queue.queue();
24 |
25 | var track_mem = argv.mem ? true : false;
26 | var runs = 0;
27 | var memstats = {
28 | max_rss:0,
29 | max_heap:0,
30 | max_heap_total:0
31 | };
32 |
33 | function run(cb) {
34 | module.helloAsync({ louder: false }, function(err, result) {
35 | if (err) {
36 | return cb(err);
37 | }
38 | ++runs;
39 | if (track_mem && runs % 1000) {
40 | var mem = process.memoryUsage();
41 | if (mem.rss > memstats.max_rss) memstats.max_rss = mem.rss;
42 | if (mem.heapTotal > memstats.max_heap_total) memstats.max_heap_total = mem.heapTotal;
43 | if (mem.heapUsed > memstats.max_heap) memstats.max_heap = mem.heapUsed;
44 | }
45 | return cb();
46 | });
47 | }
48 |
49 | // Start monitoring time before async work begins within the defer iterator below.
50 | // AsyncWorkers will kick off actual work before the defer iterator is finished,
51 | // and we want to make sure we capture the time of the work of that initial cycle.
52 | var time = +(new Date());
53 |
54 | for (var i = 0; i < argv.iterations; i++) {
55 | queue.defer(run);
56 | }
57 |
58 | queue.awaitAll(function(error) {
59 | if (error) throw error;
60 | if (runs != argv.iterations) {
61 | throw new Error('Error: did not run as expected');
62 | }
63 | // check rate
64 | time = +(new Date()) - time;
65 |
66 | if (time == 0) {
67 | console.log('Warning: ms timer not high enough resolution to reliably track rate. Try more iterations');
68 | } else {
69 | // number of milliseconds per iteration
70 | var rate = runs/(time/1000);
71 | console.log('Benchmark speed: ' + rate.toFixed(0) + ' runs/s (runs:' + runs + ' ms:' + time + ' )');
72 |
73 | if (track_mem) {
74 | console.log('Benchmark peak mem (max_rss, max_heap, max_heap_total): ', bytes(memstats.max_rss), bytes(memstats.max_heap), bytes(memstats.max_heap_total));
75 | } else {
76 | console.log('Note: pass --mem to track memory usage');
77 | }
78 | }
79 |
80 | console.log('Benchmark iterations:',argv.iterations,'concurrency:',argv.concurrency)
81 |
82 | // There may be instances when you want to assert some performance metric
83 | //assert.equal(rate > 1000, true, 'speed not at least 1000/second ( rate was ' + rate + ' runs/s )');
84 |
85 | });
--------------------------------------------------------------------------------
/bench/hello_object_async.bench.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var argv = require('minimist')(process.argv.slice(2));
4 | if (!argv.iterations || !argv.concurrency) {
5 | console.error('Please provide desired iterations, concurrency');
6 | console.error('Example: \n\tnode bench/hello_object_async.bench.js --iterations 50 --concurrency 10');
7 | console.error('Optional args: \n\t--mem (reports memory stats)');
8 | process.exit(1);
9 | }
10 |
11 | // This env var sets the libuv threadpool size.
12 | // This value is locked in once a function interacts with the threadpool
13 | // Therefore we need to set this value either in the shell or at the very
14 | // top of a JS file (like we do here)
15 | process.env.UV_THREADPOOL_SIZE = argv.concurrency;
16 |
17 | var fs = require('fs');
18 | var path = require('path');
19 | var bytes = require('bytes');
20 | var assert = require('assert')
21 | var d3_queue = require('d3-queue');
22 | var queue = d3_queue.queue();
23 | var module = require('../lib/index.js');
24 |
25 | var H = new module.HelloObjectAsync('park bench');
26 | var track_mem = argv.mem ? true : false;
27 | var runs = 0;
28 | var memstats = {
29 | max_rss:0,
30 | max_heap:0,
31 | max_heap_total:0
32 | };
33 |
34 | function run(cb) {
35 | H.helloAsync({ louder: false }, function(err, result) {
36 | if (err) {
37 | return cb(err);
38 | }
39 | ++runs;
40 | if (track_mem && runs % 1000) {
41 | var mem = process.memoryUsage();
42 | if (mem.rss > memstats.max_rss) memstats.max_rss = mem.rss;
43 | if (mem.heapTotal > memstats.max_heap_total) memstats.max_heap_total = mem.heapTotal;
44 | if (mem.heapUsed > memstats.max_heap) memstats.max_heap = mem.heapUsed;
45 | }
46 | return cb();
47 | });
48 | }
49 |
50 | // Start monitoring time before async work begins within the defer iterator below.
51 | // AsyncWorkers will kick off actual work before the defer iterator is finished,
52 | // and we want to make sure we capture the time of the work of that initial cycle.
53 | var time = +(new Date());
54 |
55 | for (var i = 0; i < argv.iterations; i++) {
56 | queue.defer(run);
57 | }
58 |
59 | queue.awaitAll(function(error) {
60 | if (error) throw error;
61 | if (runs != argv.iterations) {
62 | throw new Error("Error: did not run as expected");
63 | }
64 | // check rate
65 | time = +(new Date()) - time;
66 |
67 | if (time == 0) {
68 | console.log("Warning: ms timer not high enough resolution to reliably track rate. Try more iterations");
69 | } else {
70 | // number of milliseconds per iteration
71 | var rate = runs/(time/1000);
72 | console.log('Benchmark speed: ' + rate.toFixed(0) + ' runs/s (runs:' + runs + ' ms:' + time + ' )');
73 |
74 | if (track_mem) {
75 | console.log('Benchmark peak mem (max_rss, max_heap, max_heap_total): ', bytes(memstats.max_rss), bytes(memstats.max_heap), bytes(memstats.max_heap_total));
76 | } else {
77 | console.log('Note: pass --mem to track memory usage');
78 | }
79 | }
80 |
81 | console.log('Benchmark iterations:',argv.iterations,'concurrency:',argv.concurrency);
82 |
83 | // There may be instances when you want to assert some performance metric
84 | //assert.equal(rate > 1000, true, 'speed not at least 1000/second ( rate was ' + rate + ' runs/s )');
85 |
86 | });
--------------------------------------------------------------------------------
/binding.gyp:
--------------------------------------------------------------------------------
1 | # This file inherits default targets for Node addons, see https://github.com/nodejs/node-gyp/blob/master/addon.gypi
2 | {
3 | # https://github.com/springmeyer/gyp/blob/master/test/make_global_settings/wrapper/wrapper.gyp
4 | 'make_global_settings': [
5 | ['CXX', '<(module_root_dir)/mason_packages/.link/bin/clang++'],
6 | ['CC', '<(module_root_dir)/mason_packages/.link/bin/clang'],
7 | ['LINK', '<(module_root_dir)/mason_packages/.link/bin/clang++'],
8 | ['AR', '<(module_root_dir)/mason_packages/.link/bin/llvm-ar'],
9 | ['NM', '<(module_root_dir)/mason_packages/.link/bin/llvm-nm']
10 | ],
11 | 'includes': [ 'common.gypi' ], # brings in a default set of options that are inherited from gyp
12 | 'variables': { # custom variables we use specific to this file
13 | 'error_on_warnings%':'true', # can be overriden by a command line variable because of the % sign using "WERROR" (defined in Makefile)
14 | # Use this variable to silence warnings from mason dependencies and from NAN
15 | # It's a variable to make easy to pass to
16 | # cflags (linux) and xcode (mac)
17 | 'system_includes': [
18 | "-isystem Open`.
8 |
9 | Then to start debugging there are two ways:
10 |
11 | #### Option 1
12 |
13 | Press `Cmd + Shift + P` to open the command bar, type open `open launch.json`, and then choose `C++`.
14 |
15 | Note: the first time you do this you will need to `install` the C++ Extension and reload the app.
16 |
17 | #### Option 2
18 |
19 | Click the debug button on the right sidebar, click the `⚙` button on the right top, and then choose `C++`.
20 |
21 | 
22 |
23 | In the `launch.json` you can see some template, like this:
24 |
25 | ```json
26 | {
27 | "version": "0.2.0",
28 | "configurations": [
29 | {
30 | "name": "(lldb) Launch",
31 | "type": "cppdbg",
32 | "request": "launch",
33 | "program": "enter program name, for example ${workspaceFolder}/a.out",
34 | "args": [],
35 | "stopAtEntry": false,
36 | "cwd": "${workspaceFolder}",
37 | "environment": [],
38 | "externalConsole": true,
39 | "MIMode": "lldb"
40 | }
41 | ]
42 | }
43 | ```
44 |
45 | `launch.json` defines which program you want to run after you click the run debug button. Let's say we want run `node test/vtshaver.test.js`. In this case we need to change the configurations, put `program` to node's absolute path (you can use `which node` to find the path of current version of node), and change the `args` to `${workspaceFolder}/test/vtshaver.test.js`.
46 |
47 | Additional we want build C++ everytime before we start debug, so we add `preLaunchTask` into the config:
48 |
49 | ```
50 | "preLaunchTask": "npm: build:dev",
51 | ```
52 |
53 | Now the config file could look like this:
54 |
55 |
56 | ```json
57 | {
58 | "version": "0.2.0",
59 | "configurations": [
60 | {
61 | "name": "(lldb) Launch",
62 | "type": "cppdbg",
63 | "request": "launch",
64 | "preLaunchTask": "npm: build:dev",
65 | "program": "/Users/mapbox-mofei/.nvm/versions/node/v8.11.3/bin/node",
66 | "args": ["${workspaceFolder}/test/vtshaver.test.js"],
67 | "stopAtEntry": false,
68 | "cwd": "${workspaceFolder}",
69 | "environment": [],
70 | "externalConsole": true,
71 | "MIMode": "lldb"
72 | }
73 | ]
74 | }
75 | ```
76 |
77 | Now you can open any C++ files and click the left side of the line number to add a breakpoint, then go to the debug button on the sidebar, click the run button on the top.
78 |
79 | 
80 |
81 | Now everything is done! Debug is Done! The program will stop at the breakpoint, you can use your mouse to explore the variable. If you want your program to continue past the breakpoint, you can navigate the program using the top control box.
82 |
83 | 
84 |
--------------------------------------------------------------------------------
/docs/extended-tour.md:
--------------------------------------------------------------------------------
1 | # Extended Tour
2 | Welcome to the extended tour of node-cpp-skel. This documentation is especially handy if you're just starting out with building [Node Addon-ons](https://github.com/mapbox/cpp/blob/master/node-cpp.md) or writing C++ :tada:
3 |
4 | ## Table of Contents:
5 | - [Walkthrough of example code](extended-tour.md#walkthrough-example-code)
6 | - [What does "build" mean?](extended-tour.md#what-does-build-mean)
7 | - [Software build components](extended-tour.md#software-build-components)
8 | - [Configuration files](extended-tour.md#configuration-files)
9 | - [Autogenerated files](extended-tour.md#autogenerated-files)
10 | - [Overall flow](extended-tour.md#overall-flow)
11 | - [Clang Tools](extended-tour.md#clang-tools)
12 | - [Xcode](extended-tour.md#xcode)
13 |
14 | # Walkthrough example code
15 |
16 | This skeleton includes a few examples of how you might design your application, including standalone functions and creating Objects/Classes. Both the synchronous and asynchronous versions of each are included to give an iterative example of what the progression from sync to async looks like. Let's run through reasons why you'd design your code in these ways:
17 | 1. [Standalone function](../API.md#hello-1)
18 | 2. [Standalone asynchronous function](../API.md#helloasync-1)
19 | 3. [Object/Class](../API.md#helloobject)
20 | 4. [Asynchronous Object/Class](../API.md#helloobjectasync)
21 |
22 |
23 | ### When would you use a standalone function?
24 | A standalone function is a function that exists at the top level of the module scope rather than as a member of an object that is instantiated. So if your module is `wonderful`, a standalone function would be called like `wonderful.callme()`.
25 |
26 | A standalone function makes sense when the only data needed by the function can be easily passed as arguments. When it is not easy or clean to pass data as arguments then you should consider encapsulation, for example, exposing a function as a member of an object. One of the benefits of creating a standalone function is that it can help [separate concerns](https://en.wikipedia.org/wiki/Separation_of_concerns), which is mainly a stylistic design decision.
27 |
28 | Example:
29 | - [vtinfo](https://github.com/mapbox/vtinfo/blob/master/src/vtinfo.cpp): A synchronous standalone function that is simply getting info about a single vector tile buffer.
30 |
31 |
32 | ### When would you use an object/class?
33 | Create an object/class when you need to do some kind of data preprocessing before going into the thread pool. It's best to write your code so that the preprocessing happens _once_ as a separate operation, then continues through to the thread pool after the preprocessing is finished and the object is ready. Examples:
34 | - [node-mapnik](https://github.com/mapnik/node-mapnik/blob/fe80ce5d79c0e90cfbb5a2b992bf0ae2b8f88198/src/mapnik_map.hpp#L20): we create a Map object once, then use the object multiple times for rendering each vector tile.
35 | - [node-addon-examples](https://github.com/nodejs/node-addon-examples/tree/master/6_object_wrap/node-addon-api) for another example of what an object-focused Addon looks like.
36 |
37 | Objects/Classes are useful when you start doing more complex operations and need to consider performance more heavily, when performance constraints start to matter. Use classes to compute the value of something once, rather than every time you call a function.
38 |
39 | One step further is using an asynchronous object or class, which enables you to pass data into the threadpool. The aim is to process data in the threadpool in the most efficient way possible. [Efficiency](https://github.com/mapbox/cpp/blob/master/glossary.md#efficiency) and high performance are the main goals of the `HelloObjectAsync` example in this skel. The `HelloObjectAsync` example demonstrates high load, when _many_ objects in _many_ threads are being allocated. This scenario is where reducing unnecessary allocations really pays off, and is also why this example uses "move semantics" for even better performance.
40 | - **Move semantics**: move semantics avoid data being copied (allocating memory), to limit unnecessary memory allocation, and are most useful when working with big data.
41 |
42 | Other thoughts related to move semantics:
43 | - Always best to use move semantics instead of passing by reference, espeically with objects like [`std::string`](http://shaharmike.com/cpp/std-string/), which can be expensive.
44 | - Relatedly, best to use [`std::unique_ptr`](http://en.cppreference.com/w/cpp/memory/unique_ptr) instead of using `std::shared_ptr` because `std::unique_ptr` is non-copyable. So you're forced to avoid copying, which is a good practice.
45 |
46 |
47 | # Builds
48 |
49 | ### What does "build" mean?
50 |
51 | When you "build" your module, you are compiling and linking your C++ [source code](https://github.com/mapbox/cpp/blob/master/glossary.md#source-code) to produce a binary file that allows Node.js to load and run your module. Once loaded your C++ module can be used as if it were a Javascript module. A large list of tools come together to make this possible. In the below section we'll describe:
52 |
53 | - [Software build components](extended-tour.md##software-build-components)
54 | - Listing of [configuration files](extended-tour.md#configuration-files) for the build
55 | - Listing of [autogenerated files](extended-tour.md#autogenerated-files) created when you run a build
56 | - Overall [build flow](extended-tour.md#build-flow) of what happens when you run a build
57 |
58 | ### Software build components
59 |
60 | The primary components involved in the build
61 |
62 | #### node-pre-gyp
63 |
64 | node-pre-gyp is a javascript command line tool used in this project as a [front end](https://github.com/mapbox/cpp/blob/master/glossary.md#front-end) to [node-gyp](#node-gyp) to either compile your code or install it from binaries.
65 |
66 | It is installed as a dependency in the [package.json](../package.json).
67 |
68 | Learn more about node-pre-gyp [here](https://github.com/mapbox/node-pre-gyp)
69 |
70 | #### node-gyp
71 |
72 | node-gyp is a javascript command line tool used in this project as a [front end](https://github.com/mapbox/cpp/blob/master/glossary.md#front-end) to [gyp](#gyp).
73 |
74 | node-gyp is bundled inside [npm](#npm) and does not need to be installed separately. Although, if installed in [package.json](../package.json), that version will be used by [node-pre-gyp](#node-pre-gyp).
75 |
76 | Learn more about node-gyp [here](https://github.com/nodejs/node-gyp)
77 |
78 | #### gyp
79 |
80 | gyp is a python command line tool used in this project as a [front end](https://github.com/mapbox/cpp/blob/master/glossary.md#front-end) to [make](#make).
81 |
82 | Learn more about gyp [here](https://github.com/mapbox/cpp/blob/master/glossary.md#gyp)
83 |
84 | #### make
85 |
86 | make is a command line tool, written in C, that is installed by default on most unix systems. It is used in this project in two ways:
87 |
88 | - We provide a `Makefile` that acts as a simple entry point for developers wanting to source compile node-pre-gyp
89 | - When [node-gyp](#node-gyp) is run, it generates a set of `Makefile`s automatically which are used to call out to the [compiler](#compiler) and [linker](#linker) to assemble your binary C++ module.
90 |
91 | Learn more about make [here](https://github.com/mapbox/cpp/blob/master/glossary.md#make)
92 |
93 | #### compiler
94 |
95 | The command line program able to compile C++ source code, in this case `clang++`.
96 |
97 | Learn more about what a compiler is [here](https://github.com/mapbox/cpp/blob/master/glossary.md#compiler)
98 |
99 | #### linker
100 |
101 | The command line program able to link C++ source code, in this case also `clang++`, which acts as a [front end](https://github.com/mapbox/cpp/blob/master/glossary.md#front-end) to the [system linker](https://github.com/mapbox/cpp/blob/master/glossary.md#linker)
102 |
103 | ### Configuration files
104 |
105 | Files you will find inside this repo and their purpose. For more info look inside each file for detailed comments.
106 |
107 | - [Makefile](../Makefile) - entry point to building from source. This is invoked when you type `make` in the root directory. By default the `default` target is run which maps to the `release` target. See the comments inside the Makefile for more detail.
108 | - [binding.gyp](../binding.gyp) - JSON configuration file for [node-gyp](#node-gyp). Must be named `binding.gyp` and present in the root directory so that `npm` detects it. Will be passed to [gyp](#gyp) by [node-gyp](#node-gyp). Because [gyp](#gyp) is python and has less strict JSON parsing rules, code comments with `#` are allowed (this would not be the case if parsed with node.js).
109 | - [common.gypi](../common.gypi) - "gypi" stands for gyp include file. This is referenced by the [binding.gyp](../binding.gyp)
110 | - [package.json](../package.json) - configuration file for npm. But it also contains a custom `binary` object that is the configuration for [node-pre-gyp](#node-pre-gyp).
111 | - [lib/index.js](../lib/index.js) - entry point for the javascript module. Referenced in the `main` property in the [package.json](../package.json). This is the file that is run when the module is loaded by `require` from another module.
112 | - [scripts/setup.sh](../scripts/setup.sh) - script used to 1) install [Mason](https://github.com/mapbox/cpp/blob/master/glossary.md#mason) and [clang++](https://github.com/mapbox/cpp/blob/master/glossary.md#clang-1) and 2) create a `local.env` that can be sourced in `bash` in order to set up [Mason](https://github.com/mapbox/cpp/blob/master/glossary.md#mason) and [clang++](https://github.com/mapbox/cpp/blob/master/glossary.md#clang-1) on your PATH.
113 | - [scripts/install_deps.sh](../scripts/install_deps.sh) - script that invokes [Mason](https://github.com/mapbox/cpp/blob/master/glossary.md#mason) to install mason packages
114 | - [scripts/publish.sh](../scripts/publish.sh) - script to publish the C++ binary module with [node-pre-gyp](#node-pre-gyp). Designed to be run on [travisci.org](https://travis-ci.org/)
115 | - [.travis.yml](../.travis.yml) - configuration for this module on [travisci.org](https://travis-ci.org/). Used to test the code and publish binaries for various node versions and compiler options.
116 |
117 | Note: the `binding.gyp` file also inherits from two files that you will not find inside the node-cpp-skel repo. These are gyp include files that come from node core and node-gyp and are invoked when [`node-gyp configure` is called](https://github.com/nodejs/node-gyp/blob/a8ba5288cb25d4edcafdc75d0cd59b474b7225e8/lib/configure.js#L279-L280):
118 |
119 | - https://github.com/nodejs/node/blob/v4.x/common.gypi
120 | - https://github.com/nodejs/node-gyp/blob/master/addon.gypi
121 |
122 | ### Autogenerated files
123 |
124 | Files you will notice are created when you build from source by running `make`:
125 |
126 | - `build/` - a directory created by [node-gyp](#node-gyp) to hold a variety of autogenerated Makefiles, gyp files, and binary outputs.
127 | - `build/Release/` - directory created to hold binary files for a `Release` build. A `Release` build is the default build when you run `make`. For more info on release builds see [this definition](https://github.com/mapbox/cpp/blob/master/glossary.md#release-build)
128 | - `build/Release/module.node` - The C++ binary module, for a `Release build, in the form of a [loadable module](https://github.com/mapbox/cpp/blob/master/glossary.md#loadable-module). This file was ultimately created by the [linker](#linker) and ended up at this path thanks to [node-gyp](#node-gyp).
129 | - `lib/binding/module.node` - the final resting place for the C++ binary module. Copied to this location from either `build/Release/module.node` or `build/Debug/module.node`. This location is configured via the `module_path` variable in the [package.json](../package.json) and is used by [node-pre-gyp](#node-pre-gyp) when assembling a package to publish remotely (to allow users to install via binaries).
130 | - `build/Release/obj.target/module/src/module.o`: the [object file](https://github.com/mapbox/cpp/blob/master/glossary.md#object-file) that corresponds to the [`src/module.cpp`](../src/module.cpp).
131 | - `build/Release/obj.target/module/standalone/hello.o`: the [object file](https://github.com/mapbox/cpp/blob/master/glossary.md#object-file) that corresponds to the [`src/standalone/hello.cpp`](../src/standalone/hello.cpp).
132 | - `build/Debug/` - directory created to hold binary files for a `Debug` build. A `Debug` build is trigged when you run `make debug`. For more info on debug builds see [this definition](https://github.com/mapbox/cpp/blob/master/glossary.md#debug-build)
133 | - `build/Debug/module.node` - The C++ binary module, for a `Debug build, in the form of a [loadable module](https://github.com/mapbox/cpp/blob/master/glossary.md#loadable-module). This file was ultimately created by the [linker](#linker) and ended up at this path thanks to [node-gyp](#node-gyp).
134 |
135 |
136 |
137 | ### Overall flow
138 |
139 | The overall flow in terms of software components is:
140 |
141 | ```
142 | make -> node-pre-gyp -> node-gyp -> gyp -> make -> compiler/linker
143 | ```
144 |
145 | The overall flow, including operations, is:
146 |
147 | ```
148 | Developer (you) runs 'make'
149 | -> make reads Makefile
150 | -> Makefile has custom line that calls out to 'node-pre-gyp configure build'
151 | -> node-pre-gyp passes variables in the package.json along to 'node-gyp rebuild'
152 | -> node-gyp finds the `binding.gyp` and passes it to gyp along with other .gyp includes (addon.gypi and a common.gypi from node core)
153 | -> gyp loads the `binding.gyp` and the `common.gypi` and generates Makefiles inside `build/` directory
154 | -> node-gyp runs make in the `build/` directory
155 | -> make runs all the targets in the makefiles generated by gyp in the `build/` directory
156 | -> these makefiles run the `install_deps.sh` and invoke the compiler and linker for all sources to compile
157 | -> `install_deps.sh` puts mason packages in `/mason_packages` directory
158 | -> compiler outputs object files in `build/`
159 | -> linker outputs the loadable module in `build/`
160 | -> make copies the 'module.node` from `build/Release` to `lib/binding`
161 | ```
162 |
163 | Then the module is ready to use. What happens when it is used is:
164 |
165 | ```
166 | User of your module runs 'npm install'
167 | -> npm fetches your module
168 | -> npm notices an 'install' target that calls out to node-pre-gyp
169 | -> node-pre-gyp downloads the C++ binary from remote url (as specified in the node-pre-gyp config in the package.json)
170 | -> node-pre-gyp places the C++ binary at the ['module_path']('../lib/binding/module.node')
171 | -> the index.js reads '../lib/binding/module.node'
172 | ```
173 |
174 | This binary file `../lib/binding/module.node` is what `require()` points to within Node.js.
175 |
176 | # Clang Tools
177 |
178 | This skeleton uses two clang/llvm tools for automated formatting and static fixes.
179 |
180 | Each of these tools run within their own [Travis jobs](https://github.com/mapbox/node-cpp-skel/blob/master/.travis.yml). You can disable these Travis jobs if you'd like, by commenting them out in `.travis.yml`. This may be necessary if you're porting this skel into an already-existing project that triggers tons of clang-tidy errors, and you'd like to work through them gradually while still actively iterating on other parts of your code.
181 |
182 | ### [clang-format](https://clang.llvm.org/docs/ClangFormat.html)
183 | Automates coding style enforcement, for example whitespace, tabbing, wrapping.
184 |
185 | To run
186 | ```
187 | make format
188 | ```
189 |
190 | - Set format preferences in [`.clang-format`](https://github.com/mapbox/node-cpp-skel/blob/master/.clang-format)
191 | - Installed and run via [`/scripts/clang-format.sh`](https://github.com/mapbox/node-cpp-skel/blob/master/scripts/clang-format.sh)
192 |
193 |
194 | ### [clang-tidy](https://clang.llvm.org/extra/clang-tidy/)
195 | Lint framework that can do very powerful checks, for example bugs that can be deduced via [static analysis](https://github.com/mapbox/cpp/blob/master/glossary.md#static-analysis), unneeded copies, inefficient for-loops, and improved readability. In many cases, it can fix and modernize your code.
196 |
197 | To run
198 | ```
199 | make tidy
200 | ```
201 |
202 | - The clang-tidy tool has a large set of checks and when one fails, the error message contains the shorthand for the check name. See llvm's docs for details about what failed check is referring to. For example, see ["performance-unnecessary-copy-initialization"](https://clang.llvm.org/extra/clang-tidy/checks/performance-unnecessary-copy-initialization.html).
203 | - Set tidy preferences in [`.clang-tidy`](https://github.com/mapbox/node-cpp-skel/blob/master/.clang-tidy). When you run clang-tidy, you'll see output of a number of specific checks that tidy runs. You can add/remove any of these checks via the `.clang-tidy` file, configure these checks, and specify the files you'd like to run these checks against. The skel runs clang-tidy against everything within the `/src` directory.
204 | - This skel runs clang-tidy with the `-fix` option, which will automatically apply fixes to your code. Though some warnings will need to be fixed manually.
205 | - Installed and run via [`/scripts/clang-tidy.sh`](https://github.com/mapbox/node-cpp-skel/blob/master/scripts/clang-tidy.sh)
206 | - `NOLINT`: In the case that clang-tidy throws for code that you either want to keep as-is or can't control, you can [use `NOLINT`](https://github.com/mapbox/node-cpp-skel/blob/87c8d51f2d7d05ac44f3ea7a607f60e73a2af9c8/src/module.cpp#L43-L46) to silent clang-tidy.
207 | - Since clang-tidy must compile the code to do its checks, skel [generates](https://github.com/mapbox/node-cpp-skel/blob/master/scripts/generate_compile_commands.py) a JSON file that tells clang-tidy which files to run against and what compile command to run. This newly generated file, `/build/compile_command.json`, is created when running `make tidy`. See [clang's JSON compilation format docs](https://clang.llvm.org/docs/JSONCompilationDatabase.html) for more info.
208 |
209 |
210 | # Xcode
211 |
212 | 
213 |
214 | If you're developing on macOS and have Xcode installed, you can also type `make xcode` to generate and open an Xcode project. In the dropdown, choose `npm test` to run the npm tests. You can also add more targets by adding the appropriate lines in `Makefile`, and rerunning `make xcode`. If you are modifying `binding.gyp`, e.g. by adding more source files, make sure to rerun `make xcode` so that Xcode knows about the new source files.
215 |
--------------------------------------------------------------------------------
/docs/image/howtodebug1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/node-cpp-skel/395eb7256b042605214a9ef66bc7477a9244c0da/docs/image/howtodebug1.png
--------------------------------------------------------------------------------
/docs/image/howtodebug2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/node-cpp-skel/395eb7256b042605214a9ef66bc7477a9244c0da/docs/image/howtodebug2.png
--------------------------------------------------------------------------------
/docs/image/howtodebug3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/node-cpp-skel/395eb7256b042605214a9ef66bc7477a9244c0da/docs/image/howtodebug3.png
--------------------------------------------------------------------------------
/docs/npm-and-package-lock.md:
--------------------------------------------------------------------------------
1 | ## Using npm, package.json, and package-lock.json
2 |
3 | With updated versions of npm, there is now such thing as a `package-lock.json` file, which is now included in node-cpp-skel. Read this doc for more info, also discussion at https://github.com/mapbox/node-cpp-skel/issues/124.
4 |
5 | `package.json` defines the dependencies required by any given library. It often defines a range of acceptable version of those dependencies, for example:
6 |
7 | ```
8 | "dependencies": {
9 | "eslint": "^4.3.0"
10 | }
11 | ```
12 |
13 | ... means that any version of eslint >4.3.0 and <5 is acceptable.
14 |
15 | `package-lock.json` defines _explicit versions of dependencies that should be used_. This is useful, because by using `package-lock.json` you can be confident that the version of your dependencies deployed in production matches exactly with the versions you install in your local testing environment.
16 |
17 | Running `npm install` in a folder that contains a `package.json` file will create a `package-lock.json` file if one does not exist. **You should commit this file**.
18 |
19 | If a `package-lock.json` file exists in the repository, but some of the versions of dependencies are out-of-sync with what's specified in `package.json` then running `npm install` will update the `package-lock.json` file. This may happen if you manually edited a version of a dependency in `package.json`, which you should not do (see below).
20 |
21 | If you are creating a PR, you should notice if that PR contains changes to `package-lock.json`, and you should be able to explain in the PR why those changes are being made.
22 |
23 | To take full advantage of the explicit dependency versions specified in `package-lock.json`, don't use `npm install`. Instead, run
24 |
25 | ```
26 | npm ci
27 | ```
28 |
29 | Note: this `ci` requires at least npm >= v5.7.1 (https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable).
30 |
31 | This will remove your existing `node_modules` folder, and then install the exact versions defined by `package-lock.json`. It will **never** make changes to `package.json` or `package-lock.json`, unlike `npm install`.
32 |
33 | ### Avoid editing package.json directly
34 |
35 | If you need to change the range of acceptable versions for a dependency:
36 |
37 | ```
38 | npm install --save eslint@^4.4.8
39 | ```
40 |
41 | If you want to upgrade a dependency to the most recent version specified by the existing range in `package.json`;
42 |
43 | ```
44 | npm update eslint
45 | ```
46 |
47 | If you want to remove a dependency:
48 |
49 | ```
50 | npm remove eslint
51 | ```
52 |
--------------------------------------------------------------------------------
/docs/publishing-binaries.md:
--------------------------------------------------------------------------------
1 | # Workflow
2 |
3 | So your code is compiling, tested, benched, and ready to be shared. How to get it into the wild? This document will go through what's next.
4 |
5 | Generally speaking, the workflow for a node-addon isn't much different than publishing a regular Javascript node module. The main difference is an added step and a bit more configuration in order to handle the binary. If the concept of a binary file is new, give [this doc a gander](https://github.com/mapbox/node-cpp-skel/blob/dbc48924b3e30bba903e6b9220b0cdf2854f717f/docs/extended-tour.md#builds).
6 |
7 | The typical workflow for a regular node module may look something like this:
8 |
9 | 1. merge to master
10 | 2. git tag
11 | 3. npm publish (Now it's ready to be npm installed)
12 |
13 | The workflow for a node add-on looks very similar:
14 |
15 | 1. merge to master
16 | 2. git tag
17 | 3. publish binaries
18 | 4. npm publish
19 |
20 | Let's talk generally about the relationship between the third and fourth steps. Since your code is in C++, any projects that `npm install` your module as a dependency will need the C++ code precompiled so that Node can use your module in Javascript world. Before publishing your module to npm, you will publish your binaries by putting them on s3 (**Note**: you will likely publish multiple binaries, one for each Node version and various operating systems). This s3 location is reflected in your module's [package.json file](https://github.com/mapbox/node-cpp-skel/blob/dbc48924b3e30bba903e6b9220b0cdf2854f717f/package.json#L35). Your package.json file is also redefining [the install command](https://github.com/mapbox/node-cpp-skel/blob/dbc48924b3e30bba903e6b9220b0cdf2854f717f/package.json#L14), by running node-pre-gyp instead.
21 |
22 | [Node-pre-gyp](https://github.com/mapbox/node-pre-gyp) is responsible for installing the binary by pulling the relevant binary from s3 and placing it in the specified and expected location defined by your module's [main index.js file](https://github.com/mapbox/node-cpp-skel/blob/dbc48924b3e30bba903e6b9220b0cdf2854f717f/lib/index.js#L3). So when a project runs `require()` on your module, they are directly accessing the binary. In a bit more detail, node-pre-gyp will detect [what version of Node is being used and which operating system](https://github.com/mapbox/node-cpp-skel/blob/dbc48924b3e30bba903e6b9220b0cdf2854f717f/package.json#L37), then go to s3 to retrieve the binary that matches.
23 |
24 | Continue reading below to learn how to publish your binaries to s3 so they're ready to be installed.
25 |
26 |
27 | # Publishing Binaries
28 |
29 | It's a good idea to publish pre-built binaries of your module if you want others to be able to easily install it on their system without needing to install a compiler like g++ or clang++. Node-pre-gyp does a lot of the heavy lifting for us (like detecting which system you are building on and deploying to s3) but you'll need a few things configured to get started.
30 |
31 | #### 1) In the `package.json`, update the `"binary"` field to the appropriate s3 bucket `host`.
32 |
33 | For Mapbox staff we recommend using a host setting of `"host": "https://mapbox-node-binary.s3.amazonaws.com",` which will publish to `s3://mapbox-node-binary/`.
34 |
35 | Note: for namespaced modules the path will end up being `s3://mapbox-node-binary/@org/`.
36 |
37 | #### 2) Copy the ci.template.js
38 |
39 | Copy the `ci.template.js` from this repo into your repo and place it at `./cloudformation/ci.template.js`
40 |
41 | #### 3) Install deps for validating and managing cloudformation templates
42 |
43 | ```bash
44 | npm install -g @mapbox/cfn-config # deploying stacks
45 | npm install -g @mapbox/cloudfriend # validating and building templates
46 | ```
47 |
48 | #### 4) Create a user with permissions to upload to `s3:////`
49 |
50 | First configure your AWS creds. You will need to set at least the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` keys. And also `AWS_SESSION_TOKEN` if you are using 2-factor auth.
51 |
52 | Then run:
53 |
54 | ```bash
55 | validate-template cloudformation/ci.template.js
56 | build-template cloudformation/ci.template.js > cloudformation/ci.template
57 | ```
58 |
59 | Next we will actually create the user. But first let's discuss what happens here. In addition to creating the user we also write details about the user to a separate bucket (for east auditing purposes). In the below command we:
60 |
61 | - Create a `ci-binary-publish` user
62 | - Using the `cloudformation/ci.template`
63 | - And ask to save our stack configuration to the `cfn-config` bucket. If you are outside of Mapbox, see [you will need to pass a different bucket and also a `--template-bucket` option](https://github.com/mapbox/cfn-config#prerequisites)
64 |
65 | Now, run the command to create the user:
66 |
67 | ```
68 | cfn-config create ci-binary-publish cloudformation/ci.template -c cfn-configs
69 | ```
70 |
71 | It will prompt you, choose:
72 |
73 | - New configuration
74 | - Ready to create the stack? Y
75 |
76 | It will fail if the stack already exists. In this case you can recreate a new user by deleting the stack by running `./node_modules/.bin/cfn-config delete ci-binary-publish cloudformation/ci.template` and then creating a new one.
77 |
78 | #### 5) Get the user keys
79 |
80 | After the create step succeeds you will have a new user. You now need to get get the users `AccessKeyId` and `SecretAccessKey`.
81 |
82 | You can do this in two ways: 1) finding the keys through the AWS console, or 2) using cfn-config to show the stack information
83 |
84 | **Tokens via cfn-config**
85 |
86 | Run the command `cfn-config info ci-binary-publish` and you'll see a JSON output with `AccessKeyId` and `SecretAccessKey`.
87 |
88 | **Tokens via the AWS console**
89 |
90 | - Go to https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks?filter=active&tab=outputs
91 | - Search for `ci-binary-publish`. You should see a stack called `-ci-binary-publish`
92 | - Click the checkbox beside your `-ci-binary-publish` stack
93 | - Click the `Output` tab to access the `AccessKeyId` and `SecretAccessKey` for this new user.
94 |
95 |
96 | #### 6) Add the keys to the travis
97 |
98 | **Adding to travis UI settings**
99 |
100 | - Go to https://travis-ci.org///settings
101 | - Scroll to the bottom and find the `Environment Variables` section
102 | - Add a variable called `AWS_ACCESS_KEY_ID` and put the value of the `AccessKeyId` in it
103 | - CRITICAL: Choose `OFF` for `Display value in build log` to ensure the variables are not shown in the logs
104 | - Click `Add`
105 | - Add a variable called `AWS_SECRET_ACCESS_KEY` and put the value of the `SecretAccessKey` in it
106 | - CRITICAL: Choose `OFF` for `Display value in build log` to ensure the variables are not shown in the logs
107 | - Click `Add`
108 |
109 | #### 7) All done!
110 |
111 | Now that you have generated keys for a user that can publish to s3 and provided these keys to travis in a secure way, you should be able to publish binaries. But this should be done in an automated way. See the next section below for how to do that with travis.ci.
112 |
113 | **Publishing on Travis CI**
114 |
115 | This project includes a `script/publish.sh` command that builds binaries and publishes them to s3. This script checks your commit message for either `[publish binary]` or `[republish binary]` in order to begin publishing. This allows you to publish binaries according to the version specified in your `package.json` like this:
116 |
117 | ```
118 | git commit -m 'releasing 0.1.0 [publish binary]'
119 | ```
120 |
121 | Republishing a binary overrides the current version and must be specified with `[republish binary]`.
122 |
123 | **Adding new operating systems and node versions**
124 |
125 | The `.travis.yml` file uses the `matrix` to set up each individual job, which specifies the operating system, node version, and other environment variables for running the scripts. To add more operating systems and node versions to the binaries you publish, add another job to the matrix like this:
126 |
127 | ```yaml
128 | - os: {operating system}
129 | env: NODE="{your node version}" TARGET="Release"
130 | install: *setup
131 | script: *test
132 | after_script: *publish
133 | ```
134 |
135 | ### Dev releases
136 |
137 | You may want to test your module works correctly, in downstream dependencies, before formally publishing. To do this we recommend you:
138 |
139 | 1. Create a branch of your node c++ module
140 |
141 | 2. Modify the `version` string in your `package.json` like:
142 |
143 | ```diff
144 | diff --git a/package.json b/package.json
145 | index e00b7b5..22f7cd9 100644
146 | --- a/package.json
147 | +++ b/package.json
148 | @@ -1,6 +1,6 @@
149 | {
150 | "name": "@mapbox/node-cpp-skel",
151 | - "version": "0.1.0",
152 | + "version": "0.1.0-alpha",
153 | "description": "Skeleton for bindings to C++ libraries for Node.js using NAN",
154 | "url": "http://github.com/mapbox/node-cpp-skel",
155 | "main": "./lib/index.js",
156 | ```
157 |
158 | 3. Publishing C++ binaries by pushing a commit with `[publish binary]` per https://github.com/mapbox/node-cpp-skel/blob/master/docs/publishing-binaries.md#7-all-done
159 |
160 |
161 | 4. **Option A)** Require your module in downstream applications like:
162 |
163 | ```js
164 | "your-module": "https://github.com///tarball/",
165 | ```
166 |
167 | If you're publishing from a private repo, generate a dev release and then reference the url in the appropriate `package.json` file. For example, `zip` the repo, put to S3, and then reference the S3 url in `package.json`.
168 |
169 | **Option B)** Issue a npm dev release after the binary is published.
170 |
171 | Run `npm publish --tag dev` and then require your module in downstream applications like:
172 |
173 | ```js
174 | "your-module": "0.1.0-alpha",
175 | ```
176 |
177 | For npm dev releases, it’s good to use the `--tag ` to avoid publishing to the latest tag. If you run `npm publish` then `0.1.0-alpha` is what anyone running `npm install --save` will receive.
178 |
179 |
180 | #### Before `npm publish`
181 |
182 | Before publishing to npm, you can ensure the final packaged tarball will include what you expect. For instance, you want to avoid a large accidental file being packaged by npm and make sure the package contains all needed dependencies.
183 |
184 | Take a peek at what npm will publish by running:
185 |
186 | ```
187 | make
188 | make testpack
189 | ```
190 |
191 | This will create a tarball locally and print every file included. A couple basic checks:
192 | - make sure `.mason` is not included
193 | - make sure `node-pre-gyp` directory is included, because it is responsible for knowing where to grab the binary from s3.
194 |
195 | **Hot tips** :hot_pepper:
196 | - Node and npm versions can have differing `npm pack` and `npm publish` behaviour, so be mindful of what your environment is using
197 | - You can use the resulting tarball locally and install it within another local repo to make sure it works:
198 | ```
199 | npm install
200 | ```
201 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const {
4 | hello,
5 | helloAsync,
6 | helloPromise,
7 | HelloObject,
8 | HelloObjectAsync
9 | } = require('./binding/module.node');
10 |
11 | module.exports = {
12 | /**
13 | * This is a synchronous standalone function that logs a string.
14 | * @name hello
15 | * @returns {string}
16 | * @example
17 | * const { hello } = require('@mapbox/node-cpp-skel');
18 | * const check = hello();
19 | * console.log(check); // => "hello world"
20 | */
21 | hello,
22 |
23 | /**
24 | * This is an asynchronous standalone function that logs a string.
25 | * @name helloAsync
26 | * @param {Object} args - different ways to alter the string
27 | * @param {boolean} args.louder - adds exclamation points to the string
28 | * @param {boolean} args.buffer - returns value as a node buffer rather than a string
29 | * @param {Function} callback - from whence the hello comes, returns a string
30 | * @returns {string}
31 | * @example
32 | * const { helloAsync } = require('@mapbox/node-cpp-skel');
33 | * helloAsync({ louder: true }, function(err, result) {
34 | * if (err) throw err;
35 | * console.log(result); // => "...threads are busy async bees...hello
36 | * world!!!!"
37 | * });
38 | */
39 | helloAsync,
40 |
41 | /**
42 | * This is a function that returns a promise. It multiplies a string N times.
43 | * @name helloPromise
44 | * @param {Object} [options] - different ways to alter the string
45 | * @param {string} [options.phrase=hello] - the string to multiply
46 | * @param {Number} [options.multiply=1] - duplicate the string this number of times
47 | * @returns {Promise}
48 | * @example
49 | * const { helloPromise } = require('@mapbox/node-cpp-skel');
50 | * const result = await helloAsync({ phrase: 'Howdy', multiply: 3 });
51 | * console.log(result); // HowdyHowdyHowdy
52 | */
53 | helloPromise,
54 |
55 | /**
56 | * Synchronous class, called HelloObject
57 | * @class HelloObject
58 | * @example
59 | * const { HelloObject } = require('@mapbox/node-cpp-skel');
60 | * const Obj = new HelloObject('greg');
61 | */
62 |
63 | /**
64 | * Say hello
65 | *
66 | * @name hello
67 | * @memberof HelloObject
68 | * @returns {String}
69 | * @example
70 | * const x = Obj.hello();
71 | * console.log(x); // => '...initialized an object...hello greg'
72 | */
73 | HelloObject,
74 |
75 | /**
76 | * Asynchronous class, called HelloObjectAsync
77 | * @class HelloObjectAsync
78 | * @example
79 | * const { HelloObjectAsync } = require('@mapbox/node-cpp-skel');
80 | * const Obj = new module.HelloObjectAsync('greg');
81 | */
82 |
83 | /**
84 | * Say hello while doing expensive work in threads
85 | *
86 | * @name helloAsync
87 | * @memberof HelloObjectAsync
88 | * @param {Object} args - different ways to alter the string
89 | * @param {boolean} args.louder - adds exclamation points to the string
90 | * @param {buffer} args.buffer - returns object as a node buffer rather then string
91 | * @param {Function} callback - from whence the hello comes, returns a string
92 | * @returns {String}
93 | * @example
94 | * const { HelloObjectAsync } = require('@mapbox/node-cpp-skel');
95 | * const Obj = new HelloObjectAsync('greg');
96 | * Obj.helloAsync({ louder: true }, function(err, result) {
97 | * if (err) throw err;
98 | * console.log(result); // => '...threads are busy async bees...hello greg!!!'
99 | * });
100 | */
101 | HelloObjectAsync
102 | };
--------------------------------------------------------------------------------
/mason-versions.ini:
--------------------------------------------------------------------------------
1 | [headers]
2 | protozero=1.6.8
3 | [compiled]
4 | clang++=10.0.0
5 | clang-tidy=10.0.0
6 | clang-format=10.0.0
7 | llvm-cov=10.0.0
8 | binutils=2.35
9 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@mapbox/node-cpp-skel",
3 | "version": "0.2.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@mapbox/mason-js": {
8 | "version": "0.1.5",
9 | "resolved": "https://registry.npmjs.org/@mapbox/mason-js/-/mason-js-0.1.5.tgz",
10 | "integrity": "sha512-/XHxI8UvCARISrpc1GCIOn6JI17KC2//svFCztAzb+Vjzfq3tTDOzhrh605yusmOyL1A80plUTwUta3GSpaiMw==",
11 | "requires": {
12 | "d3-queue": "^3.0.7",
13 | "fs-extra": "^4.0.2",
14 | "minimist": "^1.2.0",
15 | "mkdirp": "^0.5.1",
16 | "needle": "^2.2.0",
17 | "npmlog": "^4.1.2",
18 | "tar": "^4.0.2"
19 | }
20 | },
21 | "@mapbox/node-pre-gyp": {
22 | "version": "1.0.8",
23 | "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz",
24 | "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==",
25 | "requires": {
26 | "detect-libc": "^1.0.3",
27 | "https-proxy-agent": "^5.0.0",
28 | "make-dir": "^3.1.0",
29 | "node-fetch": "^2.6.5",
30 | "nopt": "^5.0.0",
31 | "npmlog": "^5.0.1",
32 | "rimraf": "^3.0.2",
33 | "semver": "^7.3.5",
34 | "tar": "^6.1.11"
35 | },
36 | "dependencies": {
37 | "ansi-regex": {
38 | "version": "5.0.1",
39 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
40 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
41 | },
42 | "are-we-there-yet": {
43 | "version": "2.0.0",
44 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
45 | "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
46 | "requires": {
47 | "delegates": "^1.0.0",
48 | "readable-stream": "^3.6.0"
49 | }
50 | },
51 | "chownr": {
52 | "version": "2.0.0",
53 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
54 | "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
55 | },
56 | "fs-minipass": {
57 | "version": "2.1.0",
58 | "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
59 | "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
60 | "requires": {
61 | "minipass": "^3.0.0"
62 | }
63 | },
64 | "gauge": {
65 | "version": "3.0.2",
66 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
67 | "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
68 | "requires": {
69 | "aproba": "^1.0.3 || ^2.0.0",
70 | "color-support": "^1.1.2",
71 | "console-control-strings": "^1.0.0",
72 | "has-unicode": "^2.0.1",
73 | "object-assign": "^4.1.1",
74 | "signal-exit": "^3.0.0",
75 | "string-width": "^4.2.3",
76 | "strip-ansi": "^6.0.1",
77 | "wide-align": "^1.1.2"
78 | }
79 | },
80 | "is-fullwidth-code-point": {
81 | "version": "3.0.0",
82 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
83 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
84 | },
85 | "minipass": {
86 | "version": "3.1.6",
87 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
88 | "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
89 | "requires": {
90 | "yallist": "^4.0.0"
91 | }
92 | },
93 | "minizlib": {
94 | "version": "2.1.2",
95 | "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
96 | "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
97 | "requires": {
98 | "minipass": "^3.0.0",
99 | "yallist": "^4.0.0"
100 | }
101 | },
102 | "mkdirp": {
103 | "version": "1.0.4",
104 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
105 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
106 | },
107 | "npmlog": {
108 | "version": "5.0.1",
109 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
110 | "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
111 | "requires": {
112 | "are-we-there-yet": "^2.0.0",
113 | "console-control-strings": "^1.1.0",
114 | "gauge": "^3.0.0",
115 | "set-blocking": "^2.0.0"
116 | }
117 | },
118 | "readable-stream": {
119 | "version": "3.6.0",
120 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
121 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
122 | "requires": {
123 | "inherits": "^2.0.3",
124 | "string_decoder": "^1.1.1",
125 | "util-deprecate": "^1.0.1"
126 | }
127 | },
128 | "string-width": {
129 | "version": "4.2.3",
130 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
131 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
132 | "requires": {
133 | "emoji-regex": "^8.0.0",
134 | "is-fullwidth-code-point": "^3.0.0",
135 | "strip-ansi": "^6.0.1"
136 | }
137 | },
138 | "strip-ansi": {
139 | "version": "6.0.1",
140 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
141 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
142 | "requires": {
143 | "ansi-regex": "^5.0.1"
144 | }
145 | },
146 | "tar": {
147 | "version": "6.1.11",
148 | "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
149 | "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
150 | "requires": {
151 | "chownr": "^2.0.0",
152 | "fs-minipass": "^2.0.0",
153 | "minipass": "^3.0.0",
154 | "minizlib": "^2.1.1",
155 | "mkdirp": "^1.0.3",
156 | "yallist": "^4.0.0"
157 | }
158 | },
159 | "yallist": {
160 | "version": "4.0.0",
161 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
162 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
163 | }
164 | }
165 | },
166 | "abbrev": {
167 | "version": "1.1.1",
168 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
169 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
170 | },
171 | "agent-base": {
172 | "version": "6.0.2",
173 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
174 | "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
175 | "requires": {
176 | "debug": "4"
177 | },
178 | "dependencies": {
179 | "debug": {
180 | "version": "4.3.3",
181 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
182 | "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
183 | "requires": {
184 | "ms": "2.1.2"
185 | }
186 | },
187 | "ms": {
188 | "version": "2.1.2",
189 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
190 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
191 | }
192 | }
193 | },
194 | "ansi-regex": {
195 | "version": "2.1.1",
196 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
197 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
198 | },
199 | "aproba": {
200 | "version": "1.2.0",
201 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
202 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
203 | },
204 | "are-we-there-yet": {
205 | "version": "1.1.4",
206 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
207 | "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
208 | "requires": {
209 | "delegates": "^1.0.0",
210 | "readable-stream": "^2.0.6"
211 | }
212 | },
213 | "array-filter": {
214 | "version": "1.0.0",
215 | "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz",
216 | "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=",
217 | "dev": true
218 | },
219 | "available-typed-arrays": {
220 | "version": "1.0.2",
221 | "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz",
222 | "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==",
223 | "dev": true,
224 | "requires": {
225 | "array-filter": "^1.0.0"
226 | }
227 | },
228 | "aws-sdk": {
229 | "version": "2.840.0",
230 | "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.840.0.tgz",
231 | "integrity": "sha512-ngesHJqb0PXYjJNnCsAX4yLkR6JFQJB+3eDGwh3mYRjcq9voix5RfbCFQT1lwWu7bcMBPCrRIA2lJkkTMYXq+A==",
232 | "dev": true,
233 | "requires": {
234 | "buffer": "4.9.2",
235 | "events": "1.1.1",
236 | "ieee754": "1.1.13",
237 | "jmespath": "0.15.0",
238 | "querystring": "0.2.0",
239 | "sax": "1.2.1",
240 | "url": "0.10.3",
241 | "uuid": "3.3.2",
242 | "xml2js": "0.4.19"
243 | },
244 | "dependencies": {
245 | "sax": {
246 | "version": "1.2.1",
247 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
248 | "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=",
249 | "dev": true
250 | }
251 | }
252 | },
253 | "balanced-match": {
254 | "version": "1.0.0",
255 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
256 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
257 | },
258 | "base64-js": {
259 | "version": "1.5.1",
260 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
261 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
262 | "dev": true
263 | },
264 | "brace-expansion": {
265 | "version": "1.1.11",
266 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
267 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
268 | "requires": {
269 | "balanced-match": "^1.0.0",
270 | "concat-map": "0.0.1"
271 | }
272 | },
273 | "buffer": {
274 | "version": "4.9.2",
275 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
276 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
277 | "dev": true,
278 | "requires": {
279 | "base64-js": "^1.0.2",
280 | "ieee754": "^1.1.4",
281 | "isarray": "^1.0.0"
282 | }
283 | },
284 | "bytes": {
285 | "version": "3.1.0",
286 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
287 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
288 | "dev": true
289 | },
290 | "call-bind": {
291 | "version": "1.0.2",
292 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
293 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
294 | "dev": true,
295 | "requires": {
296 | "function-bind": "^1.1.1",
297 | "get-intrinsic": "^1.0.2"
298 | }
299 | },
300 | "chownr": {
301 | "version": "1.0.1",
302 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz",
303 | "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE="
304 | },
305 | "code-point-at": {
306 | "version": "1.1.0",
307 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
308 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
309 | },
310 | "color-support": {
311 | "version": "1.1.3",
312 | "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
313 | "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="
314 | },
315 | "concat-map": {
316 | "version": "0.0.1",
317 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
318 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
319 | },
320 | "console-control-strings": {
321 | "version": "1.1.0",
322 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
323 | "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
324 | },
325 | "core-util-is": {
326 | "version": "1.0.2",
327 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
328 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
329 | },
330 | "d3-queue": {
331 | "version": "3.0.7",
332 | "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-3.0.7.tgz",
333 | "integrity": "sha1-yTouVLQXwJWRKdfXP2z31Ckudhg="
334 | },
335 | "debug": {
336 | "version": "2.6.9",
337 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
338 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
339 | "requires": {
340 | "ms": "2.0.0"
341 | }
342 | },
343 | "deep-equal": {
344 | "version": "2.0.5",
345 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz",
346 | "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==",
347 | "dev": true,
348 | "requires": {
349 | "call-bind": "^1.0.0",
350 | "es-get-iterator": "^1.1.1",
351 | "get-intrinsic": "^1.0.1",
352 | "is-arguments": "^1.0.4",
353 | "is-date-object": "^1.0.2",
354 | "is-regex": "^1.1.1",
355 | "isarray": "^2.0.5",
356 | "object-is": "^1.1.4",
357 | "object-keys": "^1.1.1",
358 | "object.assign": "^4.1.2",
359 | "regexp.prototype.flags": "^1.3.0",
360 | "side-channel": "^1.0.3",
361 | "which-boxed-primitive": "^1.0.1",
362 | "which-collection": "^1.0.1",
363 | "which-typed-array": "^1.1.2"
364 | },
365 | "dependencies": {
366 | "isarray": {
367 | "version": "2.0.5",
368 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
369 | "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
370 | "dev": true
371 | }
372 | }
373 | },
374 | "define-properties": {
375 | "version": "1.1.3",
376 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
377 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
378 | "dev": true,
379 | "requires": {
380 | "object-keys": "^1.0.12"
381 | }
382 | },
383 | "defined": {
384 | "version": "1.0.0",
385 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
386 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
387 | "dev": true
388 | },
389 | "delegates": {
390 | "version": "1.0.0",
391 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
392 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
393 | },
394 | "detect-libc": {
395 | "version": "1.0.3",
396 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
397 | "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
398 | },
399 | "dotignore": {
400 | "version": "0.1.2",
401 | "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz",
402 | "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==",
403 | "dev": true,
404 | "requires": {
405 | "minimatch": "^3.0.4"
406 | }
407 | },
408 | "emoji-regex": {
409 | "version": "8.0.0",
410 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
411 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
412 | },
413 | "es-abstract": {
414 | "version": "1.18.0-next.2",
415 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz",
416 | "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==",
417 | "dev": true,
418 | "requires": {
419 | "call-bind": "^1.0.2",
420 | "es-to-primitive": "^1.2.1",
421 | "function-bind": "^1.1.1",
422 | "get-intrinsic": "^1.0.2",
423 | "has": "^1.0.3",
424 | "has-symbols": "^1.0.1",
425 | "is-callable": "^1.2.2",
426 | "is-negative-zero": "^2.0.1",
427 | "is-regex": "^1.1.1",
428 | "object-inspect": "^1.9.0",
429 | "object-keys": "^1.1.1",
430 | "object.assign": "^4.1.2",
431 | "string.prototype.trimend": "^1.0.3",
432 | "string.prototype.trimstart": "^1.0.3"
433 | }
434 | },
435 | "es-get-iterator": {
436 | "version": "1.1.2",
437 | "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz",
438 | "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==",
439 | "dev": true,
440 | "requires": {
441 | "call-bind": "^1.0.2",
442 | "get-intrinsic": "^1.1.0",
443 | "has-symbols": "^1.0.1",
444 | "is-arguments": "^1.1.0",
445 | "is-map": "^2.0.2",
446 | "is-set": "^2.0.2",
447 | "is-string": "^1.0.5",
448 | "isarray": "^2.0.5"
449 | },
450 | "dependencies": {
451 | "isarray": {
452 | "version": "2.0.5",
453 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
454 | "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
455 | "dev": true
456 | }
457 | }
458 | },
459 | "es-to-primitive": {
460 | "version": "1.2.1",
461 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
462 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
463 | "dev": true,
464 | "requires": {
465 | "is-callable": "^1.1.4",
466 | "is-date-object": "^1.0.1",
467 | "is-symbol": "^1.0.2"
468 | }
469 | },
470 | "events": {
471 | "version": "1.1.1",
472 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
473 | "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
474 | "dev": true
475 | },
476 | "for-each": {
477 | "version": "0.3.3",
478 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
479 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
480 | "dev": true,
481 | "requires": {
482 | "is-callable": "^1.1.3"
483 | }
484 | },
485 | "foreach": {
486 | "version": "2.0.5",
487 | "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
488 | "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
489 | "dev": true
490 | },
491 | "fs-extra": {
492 | "version": "4.0.3",
493 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
494 | "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
495 | "requires": {
496 | "graceful-fs": "^4.1.2",
497 | "jsonfile": "^4.0.0",
498 | "universalify": "^0.1.0"
499 | }
500 | },
501 | "fs-minipass": {
502 | "version": "1.2.5",
503 | "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
504 | "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
505 | "requires": {
506 | "minipass": "^2.2.1"
507 | }
508 | },
509 | "fs.realpath": {
510 | "version": "1.0.0",
511 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
512 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
513 | },
514 | "function-bind": {
515 | "version": "1.1.1",
516 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
517 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
518 | "dev": true
519 | },
520 | "gauge": {
521 | "version": "2.7.4",
522 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
523 | "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
524 | "requires": {
525 | "aproba": "^1.0.3",
526 | "console-control-strings": "^1.0.0",
527 | "has-unicode": "^2.0.0",
528 | "object-assign": "^4.1.0",
529 | "signal-exit": "^3.0.0",
530 | "string-width": "^1.0.1",
531 | "strip-ansi": "^3.0.1",
532 | "wide-align": "^1.1.0"
533 | }
534 | },
535 | "get-intrinsic": {
536 | "version": "1.1.1",
537 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
538 | "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
539 | "dev": true,
540 | "requires": {
541 | "function-bind": "^1.1.1",
542 | "has": "^1.0.3",
543 | "has-symbols": "^1.0.1"
544 | }
545 | },
546 | "glob": {
547 | "version": "7.1.6",
548 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
549 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
550 | "requires": {
551 | "fs.realpath": "^1.0.0",
552 | "inflight": "^1.0.4",
553 | "inherits": "2",
554 | "minimatch": "^3.0.4",
555 | "once": "^1.3.0",
556 | "path-is-absolute": "^1.0.0"
557 | }
558 | },
559 | "graceful-fs": {
560 | "version": "4.2.3",
561 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
562 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
563 | },
564 | "has": {
565 | "version": "1.0.3",
566 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
567 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
568 | "dev": true,
569 | "requires": {
570 | "function-bind": "^1.1.1"
571 | }
572 | },
573 | "has-symbols": {
574 | "version": "1.0.1",
575 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
576 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
577 | "dev": true
578 | },
579 | "has-unicode": {
580 | "version": "2.0.1",
581 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
582 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
583 | },
584 | "https-proxy-agent": {
585 | "version": "5.0.0",
586 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
587 | "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
588 | "requires": {
589 | "agent-base": "6",
590 | "debug": "4"
591 | },
592 | "dependencies": {
593 | "debug": {
594 | "version": "4.3.3",
595 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
596 | "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
597 | "requires": {
598 | "ms": "2.1.2"
599 | }
600 | },
601 | "ms": {
602 | "version": "2.1.2",
603 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
604 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
605 | }
606 | }
607 | },
608 | "iconv-lite": {
609 | "version": "0.4.23",
610 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
611 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
612 | "requires": {
613 | "safer-buffer": ">= 2.1.2 < 3"
614 | }
615 | },
616 | "ieee754": {
617 | "version": "1.1.13",
618 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
619 | "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
620 | "dev": true
621 | },
622 | "inflight": {
623 | "version": "1.0.6",
624 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
625 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
626 | "requires": {
627 | "once": "^1.3.0",
628 | "wrappy": "1"
629 | }
630 | },
631 | "inherits": {
632 | "version": "2.0.3",
633 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
634 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
635 | },
636 | "is-arguments": {
637 | "version": "1.1.0",
638 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz",
639 | "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==",
640 | "dev": true,
641 | "requires": {
642 | "call-bind": "^1.0.0"
643 | }
644 | },
645 | "is-bigint": {
646 | "version": "1.0.1",
647 | "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz",
648 | "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==",
649 | "dev": true
650 | },
651 | "is-boolean-object": {
652 | "version": "1.1.0",
653 | "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz",
654 | "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==",
655 | "dev": true,
656 | "requires": {
657 | "call-bind": "^1.0.0"
658 | }
659 | },
660 | "is-callable": {
661 | "version": "1.2.3",
662 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
663 | "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==",
664 | "dev": true
665 | },
666 | "is-core-module": {
667 | "version": "2.2.0",
668 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
669 | "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
670 | "dev": true,
671 | "requires": {
672 | "has": "^1.0.3"
673 | }
674 | },
675 | "is-date-object": {
676 | "version": "1.0.2",
677 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
678 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
679 | "dev": true
680 | },
681 | "is-fullwidth-code-point": {
682 | "version": "1.0.0",
683 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
684 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
685 | "requires": {
686 | "number-is-nan": "^1.0.0"
687 | }
688 | },
689 | "is-map": {
690 | "version": "2.0.2",
691 | "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
692 | "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
693 | "dev": true
694 | },
695 | "is-negative-zero": {
696 | "version": "2.0.1",
697 | "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
698 | "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==",
699 | "dev": true
700 | },
701 | "is-number-object": {
702 | "version": "1.0.4",
703 | "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz",
704 | "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==",
705 | "dev": true
706 | },
707 | "is-regex": {
708 | "version": "1.1.2",
709 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz",
710 | "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==",
711 | "dev": true,
712 | "requires": {
713 | "call-bind": "^1.0.2",
714 | "has-symbols": "^1.0.1"
715 | }
716 | },
717 | "is-set": {
718 | "version": "2.0.2",
719 | "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
720 | "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
721 | "dev": true
722 | },
723 | "is-string": {
724 | "version": "1.0.5",
725 | "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
726 | "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
727 | "dev": true
728 | },
729 | "is-symbol": {
730 | "version": "1.0.3",
731 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
732 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
733 | "dev": true,
734 | "requires": {
735 | "has-symbols": "^1.0.1"
736 | }
737 | },
738 | "is-typed-array": {
739 | "version": "1.1.4",
740 | "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.4.tgz",
741 | "integrity": "sha512-ILaRgn4zaSrVNXNGtON6iFNotXW3hAPF3+0fB1usg2jFlWqo5fEDdmJkz0zBfoi7Dgskr8Khi2xZ8cXqZEfXNA==",
742 | "dev": true,
743 | "requires": {
744 | "available-typed-arrays": "^1.0.2",
745 | "call-bind": "^1.0.0",
746 | "es-abstract": "^1.18.0-next.1",
747 | "foreach": "^2.0.5",
748 | "has-symbols": "^1.0.1"
749 | }
750 | },
751 | "is-weakmap": {
752 | "version": "2.0.1",
753 | "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
754 | "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
755 | "dev": true
756 | },
757 | "is-weakset": {
758 | "version": "2.0.1",
759 | "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz",
760 | "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==",
761 | "dev": true
762 | },
763 | "isarray": {
764 | "version": "1.0.0",
765 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
766 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
767 | },
768 | "jmespath": {
769 | "version": "0.15.0",
770 | "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
771 | "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=",
772 | "dev": true
773 | },
774 | "jsonfile": {
775 | "version": "4.0.0",
776 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
777 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
778 | "requires": {
779 | "graceful-fs": "^4.1.6"
780 | }
781 | },
782 | "lru-cache": {
783 | "version": "6.0.0",
784 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
785 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
786 | "requires": {
787 | "yallist": "^4.0.0"
788 | },
789 | "dependencies": {
790 | "yallist": {
791 | "version": "4.0.0",
792 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
793 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
794 | }
795 | }
796 | },
797 | "make-dir": {
798 | "version": "3.1.0",
799 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
800 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
801 | "requires": {
802 | "semver": "^6.0.0"
803 | },
804 | "dependencies": {
805 | "semver": {
806 | "version": "6.3.0",
807 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
808 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
809 | }
810 | }
811 | },
812 | "minimatch": {
813 | "version": "3.0.4",
814 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
815 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
816 | "requires": {
817 | "brace-expansion": "^1.1.7"
818 | }
819 | },
820 | "minimist": {
821 | "version": "1.2.5",
822 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
823 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
824 | },
825 | "minipass": {
826 | "version": "2.3.3",
827 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz",
828 | "integrity": "sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw==",
829 | "requires": {
830 | "safe-buffer": "^5.1.2",
831 | "yallist": "^3.0.0"
832 | },
833 | "dependencies": {
834 | "safe-buffer": {
835 | "version": "5.1.2",
836 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
837 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
838 | }
839 | }
840 | },
841 | "minizlib": {
842 | "version": "1.1.0",
843 | "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz",
844 | "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
845 | "requires": {
846 | "minipass": "^2.2.1"
847 | }
848 | },
849 | "mkdirp": {
850 | "version": "0.5.1",
851 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
852 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
853 | "requires": {
854 | "minimist": "0.0.8"
855 | },
856 | "dependencies": {
857 | "minimist": {
858 | "version": "0.0.8",
859 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
860 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
861 | }
862 | }
863 | },
864 | "ms": {
865 | "version": "2.0.0",
866 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
867 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
868 | },
869 | "needle": {
870 | "version": "2.2.1",
871 | "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.1.tgz",
872 | "integrity": "sha512-t/ZswCM9JTWjAdXS9VpvqhI2Ct2sL2MdY4fUXqGJaGBk13ge99ObqRksRTbBE56K+wxUXwwfZYOuZHifFW9q+Q==",
873 | "requires": {
874 | "debug": "^2.1.2",
875 | "iconv-lite": "^0.4.4",
876 | "sax": "^1.2.4"
877 | }
878 | },
879 | "node-addon-api": {
880 | "version": "4.3.0",
881 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
882 | "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
883 | },
884 | "node-fetch": {
885 | "version": "2.6.7",
886 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
887 | "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
888 | "requires": {
889 | "whatwg-url": "^5.0.0"
890 | }
891 | },
892 | "nopt": {
893 | "version": "5.0.0",
894 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
895 | "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
896 | "requires": {
897 | "abbrev": "1"
898 | }
899 | },
900 | "npmlog": {
901 | "version": "4.1.2",
902 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
903 | "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
904 | "requires": {
905 | "are-we-there-yet": "~1.1.2",
906 | "console-control-strings": "~1.1.0",
907 | "gauge": "~2.7.3",
908 | "set-blocking": "~2.0.0"
909 | }
910 | },
911 | "number-is-nan": {
912 | "version": "1.0.1",
913 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
914 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
915 | },
916 | "object-assign": {
917 | "version": "4.1.1",
918 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
919 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
920 | },
921 | "object-inspect": {
922 | "version": "1.9.0",
923 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz",
924 | "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==",
925 | "dev": true
926 | },
927 | "object-is": {
928 | "version": "1.1.4",
929 | "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz",
930 | "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==",
931 | "dev": true,
932 | "requires": {
933 | "call-bind": "^1.0.0",
934 | "define-properties": "^1.1.3"
935 | }
936 | },
937 | "object-keys": {
938 | "version": "1.1.1",
939 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
940 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
941 | "dev": true
942 | },
943 | "object.assign": {
944 | "version": "4.1.2",
945 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
946 | "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
947 | "dev": true,
948 | "requires": {
949 | "call-bind": "^1.0.0",
950 | "define-properties": "^1.1.3",
951 | "has-symbols": "^1.0.1",
952 | "object-keys": "^1.1.1"
953 | }
954 | },
955 | "once": {
956 | "version": "1.4.0",
957 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
958 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
959 | "requires": {
960 | "wrappy": "1"
961 | }
962 | },
963 | "path-is-absolute": {
964 | "version": "1.0.1",
965 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
966 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
967 | },
968 | "path-parse": {
969 | "version": "1.0.6",
970 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
971 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
972 | "dev": true
973 | },
974 | "process-nextick-args": {
975 | "version": "2.0.0",
976 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
977 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
978 | },
979 | "punycode": {
980 | "version": "1.3.2",
981 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
982 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
983 | "dev": true
984 | },
985 | "querystring": {
986 | "version": "0.2.0",
987 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
988 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
989 | "dev": true
990 | },
991 | "readable-stream": {
992 | "version": "2.3.6",
993 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
994 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
995 | "requires": {
996 | "core-util-is": "~1.0.0",
997 | "inherits": "~2.0.3",
998 | "isarray": "~1.0.0",
999 | "process-nextick-args": "~2.0.0",
1000 | "safe-buffer": "~5.1.1",
1001 | "string_decoder": "~1.1.1",
1002 | "util-deprecate": "~1.0.1"
1003 | },
1004 | "dependencies": {
1005 | "string_decoder": {
1006 | "version": "1.1.1",
1007 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
1008 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
1009 | "requires": {
1010 | "safe-buffer": "~5.1.0"
1011 | }
1012 | }
1013 | }
1014 | },
1015 | "regexp.prototype.flags": {
1016 | "version": "1.3.1",
1017 | "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz",
1018 | "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==",
1019 | "dev": true,
1020 | "requires": {
1021 | "call-bind": "^1.0.2",
1022 | "define-properties": "^1.1.3"
1023 | }
1024 | },
1025 | "resolve": {
1026 | "version": "1.19.0",
1027 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
1028 | "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
1029 | "dev": true,
1030 | "requires": {
1031 | "is-core-module": "^2.1.0",
1032 | "path-parse": "^1.0.6"
1033 | }
1034 | },
1035 | "resumer": {
1036 | "version": "0.0.0",
1037 | "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz",
1038 | "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=",
1039 | "dev": true,
1040 | "requires": {
1041 | "through": "~2.3.4"
1042 | }
1043 | },
1044 | "rimraf": {
1045 | "version": "3.0.2",
1046 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
1047 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
1048 | "requires": {
1049 | "glob": "^7.1.3"
1050 | }
1051 | },
1052 | "safe-buffer": {
1053 | "version": "5.1.2",
1054 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1055 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
1056 | },
1057 | "safer-buffer": {
1058 | "version": "2.1.2",
1059 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1060 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1061 | },
1062 | "sax": {
1063 | "version": "1.2.4",
1064 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
1065 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
1066 | },
1067 | "semver": {
1068 | "version": "7.3.5",
1069 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
1070 | "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
1071 | "requires": {
1072 | "lru-cache": "^6.0.0"
1073 | }
1074 | },
1075 | "set-blocking": {
1076 | "version": "2.0.0",
1077 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
1078 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
1079 | },
1080 | "side-channel": {
1081 | "version": "1.0.4",
1082 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
1083 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
1084 | "dev": true,
1085 | "requires": {
1086 | "call-bind": "^1.0.0",
1087 | "get-intrinsic": "^1.0.2",
1088 | "object-inspect": "^1.9.0"
1089 | }
1090 | },
1091 | "signal-exit": {
1092 | "version": "3.0.2",
1093 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
1094 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
1095 | },
1096 | "string-width": {
1097 | "version": "1.0.2",
1098 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
1099 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
1100 | "requires": {
1101 | "code-point-at": "^1.0.0",
1102 | "is-fullwidth-code-point": "^1.0.0",
1103 | "strip-ansi": "^3.0.0"
1104 | }
1105 | },
1106 | "string.prototype.trim": {
1107 | "version": "1.2.3",
1108 | "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.3.tgz",
1109 | "integrity": "sha512-16IL9pIBA5asNOSukPfxX2W68BaBvxyiRK16H3RA/lWW9BDosh+w7f+LhomPHpXJ82QEe7w7/rY/S1CV97raLg==",
1110 | "dev": true,
1111 | "requires": {
1112 | "call-bind": "^1.0.0",
1113 | "define-properties": "^1.1.3",
1114 | "es-abstract": "^1.18.0-next.1"
1115 | }
1116 | },
1117 | "string.prototype.trimend": {
1118 | "version": "1.0.3",
1119 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz",
1120 | "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==",
1121 | "dev": true,
1122 | "requires": {
1123 | "call-bind": "^1.0.0",
1124 | "define-properties": "^1.1.3"
1125 | }
1126 | },
1127 | "string.prototype.trimstart": {
1128 | "version": "1.0.3",
1129 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz",
1130 | "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==",
1131 | "dev": true,
1132 | "requires": {
1133 | "call-bind": "^1.0.0",
1134 | "define-properties": "^1.1.3"
1135 | }
1136 | },
1137 | "string_decoder": {
1138 | "version": "1.3.0",
1139 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
1140 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
1141 | "requires": {
1142 | "safe-buffer": "~5.2.0"
1143 | },
1144 | "dependencies": {
1145 | "safe-buffer": {
1146 | "version": "5.2.1",
1147 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1148 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
1149 | }
1150 | }
1151 | },
1152 | "strip-ansi": {
1153 | "version": "3.0.1",
1154 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
1155 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
1156 | "requires": {
1157 | "ansi-regex": "^2.0.0"
1158 | }
1159 | },
1160 | "tape": {
1161 | "version": "5.1.1",
1162 | "resolved": "https://registry.npmjs.org/tape/-/tape-5.1.1.tgz",
1163 | "integrity": "sha512-ujhT+ZJPqSGY9Le02mIGBnyWo7Ks05FEGS9PnlqECr3sM3KyV4CSCXAvSBJKMN+t+aZYLKEFUEo0l4wFJMhppQ==",
1164 | "dev": true,
1165 | "requires": {
1166 | "call-bind": "^1.0.0",
1167 | "deep-equal": "^2.0.5",
1168 | "defined": "^1.0.0",
1169 | "dotignore": "^0.1.2",
1170 | "for-each": "^0.3.3",
1171 | "glob": "^7.1.6",
1172 | "has": "^1.0.3",
1173 | "inherits": "^2.0.4",
1174 | "is-regex": "^1.1.1",
1175 | "minimist": "^1.2.5",
1176 | "object-inspect": "^1.9.0",
1177 | "object-is": "^1.1.4",
1178 | "object.assign": "^4.1.2",
1179 | "resolve": "^1.19.0",
1180 | "resumer": "^0.0.0",
1181 | "string.prototype.trim": "^1.2.3",
1182 | "through": "^2.3.8"
1183 | },
1184 | "dependencies": {
1185 | "inherits": {
1186 | "version": "2.0.4",
1187 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1188 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1189 | "dev": true
1190 | }
1191 | }
1192 | },
1193 | "tar": {
1194 | "version": "4.4.4",
1195 | "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.4.tgz",
1196 | "integrity": "sha512-mq9ixIYfNF9SK0IS/h2HKMu8Q2iaCuhDDsZhdEag/FHv8fOaYld4vN7ouMgcSSt5WKZzPs8atclTcJm36OTh4w==",
1197 | "requires": {
1198 | "chownr": "^1.0.1",
1199 | "fs-minipass": "^1.2.5",
1200 | "minipass": "^2.3.3",
1201 | "minizlib": "^1.1.0",
1202 | "mkdirp": "^0.5.0",
1203 | "safe-buffer": "^5.1.2",
1204 | "yallist": "^3.0.2"
1205 | },
1206 | "dependencies": {
1207 | "safe-buffer": {
1208 | "version": "5.1.2",
1209 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1210 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
1211 | }
1212 | }
1213 | },
1214 | "through": {
1215 | "version": "2.3.8",
1216 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
1217 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
1218 | "dev": true
1219 | },
1220 | "tr46": {
1221 | "version": "0.0.3",
1222 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
1223 | "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
1224 | },
1225 | "universalify": {
1226 | "version": "0.1.2",
1227 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
1228 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
1229 | },
1230 | "url": {
1231 | "version": "0.10.3",
1232 | "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
1233 | "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
1234 | "dev": true,
1235 | "requires": {
1236 | "punycode": "1.3.2",
1237 | "querystring": "0.2.0"
1238 | }
1239 | },
1240 | "util-deprecate": {
1241 | "version": "1.0.2",
1242 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
1243 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
1244 | },
1245 | "uuid": {
1246 | "version": "3.3.2",
1247 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
1248 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
1249 | "dev": true
1250 | },
1251 | "webidl-conversions": {
1252 | "version": "3.0.1",
1253 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
1254 | "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
1255 | },
1256 | "whatwg-url": {
1257 | "version": "5.0.0",
1258 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
1259 | "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
1260 | "requires": {
1261 | "tr46": "~0.0.3",
1262 | "webidl-conversions": "^3.0.0"
1263 | }
1264 | },
1265 | "which-boxed-primitive": {
1266 | "version": "1.0.2",
1267 | "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
1268 | "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
1269 | "dev": true,
1270 | "requires": {
1271 | "is-bigint": "^1.0.1",
1272 | "is-boolean-object": "^1.1.0",
1273 | "is-number-object": "^1.0.4",
1274 | "is-string": "^1.0.5",
1275 | "is-symbol": "^1.0.3"
1276 | }
1277 | },
1278 | "which-collection": {
1279 | "version": "1.0.1",
1280 | "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
1281 | "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
1282 | "dev": true,
1283 | "requires": {
1284 | "is-map": "^2.0.1",
1285 | "is-set": "^2.0.1",
1286 | "is-weakmap": "^2.0.1",
1287 | "is-weakset": "^2.0.1"
1288 | }
1289 | },
1290 | "which-typed-array": {
1291 | "version": "1.1.4",
1292 | "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.4.tgz",
1293 | "integrity": "sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==",
1294 | "dev": true,
1295 | "requires": {
1296 | "available-typed-arrays": "^1.0.2",
1297 | "call-bind": "^1.0.0",
1298 | "es-abstract": "^1.18.0-next.1",
1299 | "foreach": "^2.0.5",
1300 | "function-bind": "^1.1.1",
1301 | "has-symbols": "^1.0.1",
1302 | "is-typed-array": "^1.1.3"
1303 | }
1304 | },
1305 | "wide-align": {
1306 | "version": "1.1.2",
1307 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
1308 | "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
1309 | "requires": {
1310 | "string-width": "^1.0.2"
1311 | }
1312 | },
1313 | "wrappy": {
1314 | "version": "1.0.2",
1315 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1316 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
1317 | },
1318 | "xml2js": {
1319 | "version": "0.4.19",
1320 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
1321 | "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
1322 | "dev": true,
1323 | "requires": {
1324 | "sax": ">=0.6.0",
1325 | "xmlbuilder": "~9.0.1"
1326 | }
1327 | },
1328 | "xmlbuilder": {
1329 | "version": "9.0.7",
1330 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
1331 | "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
1332 | "dev": true
1333 | },
1334 | "yallist": {
1335 | "version": "3.0.2",
1336 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
1337 | "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
1338 | }
1339 | }
1340 | }
1341 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@mapbox/node-cpp-skel",
3 | "version": "0.2.0",
4 | "description": "Skeleton for bindings to C++ libraries for Node.js using N-API (node-addon-api)",
5 | "url": "http://github.com/mapbox/node-cpp-skel",
6 | "main": "./lib/index.js",
7 | "repository": {
8 | "type": "git",
9 | "url": "git@github.com:mapbox/node-cpp-skel.git"
10 | },
11 | "scripts": {
12 | "test": "tape test/*.test.js",
13 | "install": "node-pre-gyp install --fallback-to-build",
14 | "docs": "documentation build ./lib/index.js -f md > API.md"
15 | },
16 | "author": "Mapbox",
17 | "license": "ISC",
18 | "dependencies": {
19 | "@mapbox/mason-js": "^0.1.5",
20 | "@mapbox/node-pre-gyp": "^1.0.8",
21 | "node-addon-api": "^4.3.0"
22 | },
23 | "devDependencies": {
24 | "aws-sdk": "^2.840.0",
25 | "bytes": "^3.1.0",
26 | "d3-queue": "^3.0.7",
27 | "minimist": "^1.2.5",
28 | "tape": "^5.1.1"
29 | },
30 | "binary": {
31 | "module_name": "module",
32 | "module_path": "./lib/binding/",
33 | "host": "https://mapbox-node-binary.s3.amazonaws.com",
34 | "remote_path": "./{name}/v{version}/{configuration}/{toolset}/",
35 | "package_name": "{platform}-{arch}.tar.gz"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/scripts/clang-format.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | : '
7 |
8 | Runs clang-format on the code in src/
9 |
10 | Return `1` if there are files to be formatted, and automatically formats them.
11 |
12 | Returns `0` if everything looks properly formatted.
13 |
14 | '
15 |
16 | PATH_TO_FORMAT_SCRIPT="$(pwd)/mason_packages/.link/bin/clang-format"
17 |
18 | # Run clang-format on all cpp and hpp files in the /src directory
19 | find src/ -type f -name '*.hpp' -o -name '*.cpp' \
20 | | xargs -I{} ${PATH_TO_FORMAT_SCRIPT} -i -style=file {}
21 |
22 | # Print list of modified files
23 | dirty=$(git ls-files --modified src/)
24 |
25 | if [[ $dirty ]]; then
26 | echo "The following files have been modified:"
27 | echo $dirty
28 | git diff
29 | exit 1
30 | else
31 | exit 0
32 | fi
--------------------------------------------------------------------------------
/scripts/clang-tidy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | # https://clang.llvm.org/extra/clang-tidy/
7 |
8 | : '
9 | Runs clang-tidy on the code in src/
10 | Return `1` if there are files automatically fixed by clang-tidy.
11 | Returns `0` if no fixes by clang-tidy.
12 | TODO: should also return non-zero if clang-tidy emits warnings
13 | or errors about things it cannot automatically fix. However I cannot
14 | figure out how to get this working yet as it seems that clang-tidy
15 | always returns 0 even on errors.
16 | '
17 |
18 | PATH_TO_CLANG_TIDY_SCRIPT="$(pwd)/mason_packages/.link/share/run-clang-tidy.py"
19 | # make sure that run-clang-tidy.py can find the right clang-tidy
20 | export PATH=$(pwd)/mason_packages/.link/bin:${PATH}
21 |
22 | # build the compile_commands.json file if it does not exist
23 | if [[ ! -f build/compile_commands.json ]]; then
24 | # We need to clean otherwise when we make the project
25 | # will will not see all the compile commands
26 | make clean
27 | # Create the build directory to put the compile_commands in
28 | # We do this first to ensure it is there to start writing to
29 | # immediately (make make not create it right away)
30 | mkdir -p build
31 | # Run make, pipe the output to the generate_compile_commands.py
32 | # and drop them in a place that clang-tidy will automatically find them
33 | RESULT=0
34 | make | tee /tmp/make-node-cpp-skel-build-output.txt || RESULT=$?
35 | if [[ ${RESULT} != 0 ]]; then
36 | echo "Build failed, could not generate compile commands for clang-tidy, aborting!"
37 | exit ${RESULT}
38 | else
39 | cat /tmp/make-node-cpp-skel-build-output.txt | scripts/generate_compile_commands.py > build/compile_commands.json
40 | fi
41 |
42 | fi
43 |
44 | # change into the build directory so that clang-tidy can find the files
45 | # at the right paths (since this is where the actual build happens)
46 | cd build
47 | ${PATH_TO_CLANG_TIDY_SCRIPT} -fix
48 | cd ../
49 |
50 | # Print list of modified files
51 | dirty=$(git ls-files --modified src/)
52 |
53 | if [[ $dirty ]]; then
54 | echo "The following files have been modified:"
55 | echo $dirty
56 | git diff
57 | exit 1
58 | else
59 | exit 0
60 | fi
61 |
--------------------------------------------------------------------------------
/scripts/coverage.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | # http://clang.llvm.org/docs/UsersManual.html#profiling-with-instrumentation
7 | # https://www.bignerdranch.com/blog/weve-got-you-covered/
8 |
9 | make clean
10 | export CXXFLAGS="-fprofile-instr-generate -fcoverage-mapping"
11 | export LDFLAGS="-fprofile-instr-generate"
12 | make debug
13 | rm -f *profraw
14 | rm -f *gcov
15 | rm -f *profdata
16 | LLVM_PROFILE_FILE="code-%p.profraw" npm test
17 | CXX_MODULE=$(./node_modules/.bin/node-pre-gyp reveal module --silent)
18 | export PATH=$(pwd)/mason_packages/.link/bin/:${PATH}
19 | llvm-profdata merge -output=code.profdata code-*.profraw
20 | llvm-cov report ${CXX_MODULE} -instr-profile=code.profdata -use-color
21 | llvm-cov show ${CXX_MODULE} -instr-profile=code.profdata src/*.cpp -filename-equivalence -use-color
22 | llvm-cov show ${CXX_MODULE} -instr-profile=code.profdata src/*.cpp -filename-equivalence -use-color --format html > /tmp/coverage.html
23 | echo "open /tmp/coverage.html for HTML version of this report"
24 |
--------------------------------------------------------------------------------
/scripts/create_scheme.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | CONTAINER=build/binding.xcodeproj
7 | OUTPUT="${CONTAINER}/xcshareddata/xcschemes/${SCHEME_NAME}.xcscheme"
8 |
9 | # Required ENV vars:
10 | # - SCHEME_TYPE: type of the scheme
11 | # - SCHEME_NAME: name of the scheme
12 |
13 | # Optional ENV vars:
14 | # - NODE_ARGUMENT (defaults to "")
15 | # - BUILDABLE_NAME (defaults ot SCHEME_NAME)
16 | # - BLUEPRINT_NAME (defaults ot SCHEME_NAME)
17 |
18 |
19 | # Try to reuse the existing Blueprint ID if the scheme already exists.
20 | if [ -f "${OUTPUT}" ]; then
21 | BLUEPRINT_ID=$(sed -n "s/[ \t]*BlueprintIdentifier *= *\"\([A-Z0-9]\{24\}\)\"/\\1/p" "${OUTPUT}" | head -1)
22 | fi
23 |
24 | NODE_ARGUMENT=${NODE_ARGUMENT:-}
25 | BLUEPRINT_ID=${BLUEPRINT_ID:-$(hexdump -n 12 -v -e '/1 "%02X"' /dev/urandom)}
26 | BUILDABLE_NAME=${BUILDABLE_NAME:-${SCHEME_NAME}}
27 | BLUEPRINT_NAME=${BLUEPRINT_NAME:-${SCHEME_NAME}}
28 |
29 | mkdir -p "${CONTAINER}/xcshareddata/xcschemes"
30 |
31 | sed "\
32 | s#{{BLUEPRINT_ID}}#${BLUEPRINT_ID}#;\
33 | s#{{BLUEPRINT_NAME}}#${BLUEPRINT_NAME}#;\
34 | s#{{BUILDABLE_NAME}}#${BUILDABLE_NAME}#;\
35 | s#{{CONTAINER}}#${CONTAINER}#;\
36 | s#{{WORKING_DIRECTORY}}#$(pwd)#;\
37 | s#{{NODE_PATH}}#$(dirname `which node`)#;\
38 | s#{{NODE_ARGUMENT}}#${NODE_ARGUMENT}#" \
39 | scripts/${SCHEME_TYPE}.xcscheme > "${OUTPUT}"
40 |
--------------------------------------------------------------------------------
/scripts/generate_compile_commands.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import sys
4 | import json
5 | import os
6 | import re
7 |
8 | # Script to generate compile_commands.json based on Makefile output
9 | # Works by accepting Makefile output from stdin, parsing it, and
10 | # turning into json records. These are then printed to stdout.
11 | # More details on the compile_commands format at:
12 | # https://clang.llvm.org/docs/JSONCompilationDatabase.html
13 | #
14 | # Note: make must be run in verbose mode, e.g. V=1 make or VERBOSE=1 make
15 | #
16 | # Usage with node-cpp-skel:
17 | #
18 | # make | ./scripts/generate_compile_commands.py > build/compile_commands.json
19 |
20 | # These work for node-cpp-skel to detect the files being compiled
21 | # They may need to be modified if you adapt this to another tool
22 | matcher = re.compile('^(.*) (.+cpp)\n')
23 | build_dir = os.path.join(os.getcwd(),"build")
24 | TOKEN_DENOTING_COMPILED_FILE='NODE_GYP_MODULE_NAME'
25 |
26 | def generate():
27 | compile_commands = []
28 | for line in sys.stdin.readlines():
29 | if TOKEN_DENOTING_COMPILED_FILE in line:
30 | match = matcher.match(line)
31 | if match:
32 | compile_commands.append({
33 | "directory": build_dir,
34 | "command": line.strip(),
35 | "file": os.path.normpath(os.path.join(build_dir,match.group(2)))
36 | })
37 | print(json.dumps(compile_commands,indent=4))
38 |
39 | if __name__ == '__main__':
40 | generate()
41 |
--------------------------------------------------------------------------------
/scripts/library.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/scripts/liftoff.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 |
5 | # First create new repo on GitHub and copy the SSH repo url
6 | # Then run "./scripts/liftoff.sh" from within your local node-cpp-skel root directory
7 | # and it will create your new local project repo side by side with node-cpp-skel directory
8 |
9 | echo "What is the name of your new project? "
10 | read name
11 | echo "What is the remote repo url for your new project? "
12 | read url
13 |
14 | mkdir ../$name
15 | cp -R ../node-cpp-skel/. ../$name/
16 | cd ../$name/
17 | rm -rf .git
18 | git init
19 |
20 | git checkout -b node-cpp-skel-port
21 | git add .
22 | git commit -m "Port from node-cpp-skel"
23 | git remote add origin $url
24 | git push -u origin node-cpp-skel-port
25 |
26 | # Perhaps useful for fresh start, also check out https://github.com/mapbox/node-cpp-skel#add-custom-code
27 | # cp /dev/null CHANGELOG.md
28 | # cp /dev/null README.md
--------------------------------------------------------------------------------
/scripts/node.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
46 |
49 |
50 |
51 |
57 |
58 |
59 |
60 |
63 |
64 |
65 |
66 |
70 |
71 |
72 |
73 |
74 |
75 |
81 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/scripts/publish.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | export COMMIT_MESSAGE=$(git log --format=%B --no-merges -n 1 | tr -d '\n')
7 |
8 | # `is_pr_merge` is designed to detect if a gitsha represents a normal
9 | # push commit (to any branch) or whether it represents travis attempting
10 | # to merge between the origin and the upstream branch.
11 | # For more details see: https://docs.travis-ci.com/user/pull-requests
12 | function is_pr_merge() {
13 | # Get the commit message via git log
14 | # This should always be the exactly the text the developer provided
15 | local COMMIT_LOG=${COMMIT_MESSAGE}
16 |
17 | # Get the commit message via git show
18 | # If the gitsha represents a merge then this will
19 | # look something like "Merge e3b1981 into 615d2a3"
20 | # Otherwise it will be the same as the "git log" output
21 | export COMMIT_SHOW=$(git show -s --format=%B | tr -d '\n')
22 |
23 | if [[ "${COMMIT_LOG}" != "${COMMIT_SHOW}" ]]; then
24 | echo true
25 | fi
26 | }
27 |
28 | # Detect if this commit represents a tag. This is useful
29 | # to detect if we are on a travis job that is running due to
30 | # "git tags --push". In this case we don't want to publish even
31 | # if [publish binary] is present since that should refer only to the
32 | # previously job that ran for that commit and not the tag made
33 | function is_tag_commit() {
34 | export COMMIT_MATCHES_KNOWN_TAG=$(git describe --exact-match $(git rev-parse HEAD) 2> /dev/null)
35 | if [[ ${COMMIT_MATCHES_KNOWN_TAG} ]]; then
36 | echo true
37 | fi
38 | }
39 |
40 | # `publish` is used to publish binaries to s3 via commit messages if:
41 | # - the commit message includes [publish binary]
42 | # - the commit message includes [republish binary]
43 | # - the commit is not a pr_merge (checked with `is_pr_merge` function)
44 | function publish() {
45 | echo "dumping binary meta..."
46 | ./node_modules/.bin/node-pre-gyp reveal --loglevel=error $@
47 |
48 | echo "determining publishing status..."
49 |
50 | if [[ $(is_pr_merge) ]]; then
51 | echo "Skipping publishing because this is a PR merge commit"
52 | elif [[ $(is_tag_commit) ]]; then
53 | echo "Skipping publishing because this is a tag"
54 | else
55 | echo "Commit message was: '${COMMIT_MESSAGE}'"
56 |
57 | if [[ ${COMMIT_MESSAGE} =~ "[publish binary]" ]]; then
58 | echo "Publishing"
59 | ./node_modules/.bin/node-pre-gyp package publish $@
60 | elif [[ ${COMMIT_MESSAGE} =~ "[republish binary]" ]]; then
61 | echo "Re-Publishing"
62 | ./node_modules/.bin/node-pre-gyp package unpublish publish $@
63 | else
64 | echo "Skipping publishing since we did not detect either [publish binary] or [republish binary] in commit message"
65 | fi
66 | fi
67 | }
68 |
69 | function usage() {
70 | >&2 echo "Usage"
71 | >&2 echo ""
72 | >&2 echo "$ ./scripts/publish.sh "
73 | >&2 echo ""
74 | >&2 echo "All args are forwarded to node-pre-gyp like --debug"
75 | >&2 echo ""
76 | exit 1
77 | }
78 |
79 | # https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash
80 | for i in "$@"
81 | do
82 | case $i in
83 | -h | --help)
84 | usage
85 | shift
86 | ;;
87 | *)
88 | ;;
89 | esac
90 | done
91 |
92 | publish $@
93 |
--------------------------------------------------------------------------------
/scripts/sanitize.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | : '
7 |
8 | Rebuilds the code with the sanitizers and runs the tests
9 |
10 | '
11 |
12 | # See https://github.com/mapbox/node-cpp-skel/blob/master/docs/extended-tour.md#configuration-files
13 |
14 | make clean
15 |
16 | # https://github.com/google/sanitizers/wiki/AddressSanitizerAsDso
17 | SHARED_LIB_EXT=.so
18 | if [[ $(uname -s) == 'Darwin' ]]; then
19 | SHARED_LIB_EXT=.dylib
20 | fi
21 |
22 | export MASON_LLVM_RT_PRELOAD=$(pwd)/$(ls mason_packages/.link/lib/clang/*/lib/*/libclang_rt.asan*${SHARED_LIB_EXT})
23 | SUPPRESSION_FILE="/tmp/leak_suppressions.txt"
24 | echo "leak:__strdup" > ${SUPPRESSION_FILE}
25 | echo "leak:v8::internal" >> ${SUPPRESSION_FILE}
26 | echo "leak:node::CreateEnvironment" >> ${SUPPRESSION_FILE}
27 | echo "leak:node::Start" >> ${SUPPRESSION_FILE}
28 | echo "leak:node::Init" >> ${SUPPRESSION_FILE}
29 | # Suppress leak related to https://github.com/libuv/libuv/pull/2480
30 | echo "leak:uv__set_process_title_platform_init" >> ${SUPPRESSION_FILE}
31 | export ASAN_SYMBOLIZER_PATH=$(pwd)/mason_packages/.link/bin/llvm-symbolizer
32 | export MSAN_SYMBOLIZER_PATH=$(pwd)/mason_packages/.link/bin/llvm-symbolizer
33 | export UBSAN_OPTIONS=print_stacktrace=1
34 | export LSAN_OPTIONS=suppressions=${SUPPRESSION_FILE}
35 | export ASAN_OPTIONS=detect_leaks=1:symbolize=1:abort_on_error=1:detect_container_overflow=1:check_initialization_order=1:detect_stack_use_after_return=1
36 | export MASON_SANITIZE="-fsanitize=address,undefined,integer,leak -fno-sanitize=vptr,function"
37 | export MASON_SANITIZE_CXXFLAGS="${MASON_SANITIZE} -fno-sanitize=vptr,function -fsanitize-address-use-after-scope -fno-omit-frame-pointer -fno-common"
38 | export MASON_SANITIZE_LDFLAGS="${MASON_SANITIZE}"
39 | # Note: to build without stopping on errors remove the -fno-sanitize-recover=all flag
40 | # You might want to do this if there are multiple errors and you want to see them all before fixing
41 | export CXXFLAGS="${MASON_SANITIZE_CXXFLAGS} ${CXXFLAGS:-} -fno-sanitize-recover=all"
42 | export LDFLAGS="${MASON_SANITIZE_LDFLAGS} ${LDFLAGS:-}"
43 | make debug
44 | export ASAN_OPTIONS=fast_unwind_on_malloc=0:${ASAN_OPTIONS}
45 | if [[ $(uname -s) == 'Darwin' ]]; then
46 | # NOTE: we must call node directly here rather than `npm test`
47 | # because OS X blocks `DYLD_INSERT_LIBRARIES` being inherited by sub shells
48 | # If this is not done right we'll see
49 | # ==18464==ERROR: Interceptors are not working. This may be because AddressSanitizer is loaded too late (e.g. via dlopen).
50 | #
51 | # See https://github.com/mapbox/node-cpp-skel/issues/122
52 | DYLD_INSERT_LIBRARIES=${MASON_LLVM_RT_PRELOAD} \
53 | node node_modules/.bin/$(node -e "console.log(require('./package.json').scripts.test)") test/*test.js
54 | else
55 | LD_PRELOAD=${MASON_LLVM_RT_PRELOAD} \
56 | npm test
57 | fi
58 |
--------------------------------------------------------------------------------
/src/cpu_intensive_task.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | namespace detail {
9 |
10 | // simulate CPU intensive task
11 | inline std::unique_ptr> do_expensive_work(std::string const& name, bool louder)
12 | {
13 | std::this_thread::sleep_for(std::chrono::milliseconds(100));
14 | std::string str = "...threads are busy async bees...hello " + name;
15 | std::unique_ptr> result = std::make_unique>(str.begin(), str.end());
16 | if (louder)
17 | {
18 | result->push_back('!');
19 | result->push_back('!');
20 | result->push_back('!');
21 | result->push_back('!');
22 | }
23 | return result;
24 | }
25 |
26 | } // namespace detail
27 |
--------------------------------------------------------------------------------
/src/module.cpp:
--------------------------------------------------------------------------------
1 | #include "object_async/hello_async.hpp"
2 | #include "object_sync/hello.hpp"
3 | #include "standalone/hello.hpp"
4 | #include "standalone_async/hello_async.hpp"
5 | #include "standalone_promise/hello_promise.hpp"
6 | #include
7 | // #include "your_code.hpp"
8 |
9 | Napi::Object init(Napi::Env env, Napi::Object exports)
10 | {
11 | // expose hello method
12 | exports.Set(Napi::String::New(env, "hello"), Napi::Function::New(env, standalone::hello));
13 |
14 | // expose helloAsync method
15 | exports.Set(Napi::String::New(env, "helloAsync"), Napi::Function::New(env, standalone_async::helloAsync));
16 |
17 | // expose helloPromise method
18 | exports.Set(Napi::String::New(env, "helloPromise"), Napi::Function::New(env, standalone_promise::helloPromise));
19 |
20 | // expose HelloObject class
21 | object_sync::HelloObject::Init(env, exports);
22 |
23 | // expose HelloObjectAsync class
24 | object_async::HelloObjectAsync::Init(env, exports);
25 |
26 | return exports;
27 | /**
28 | * You may have noticed there are multiple "hello" functions as part of this
29 | * module.
30 | * They are exposed a bit differently.
31 | * 1) standalone::hello // exposed above
32 | * 2) HelloObject.hello // exposed in object_sync/hello.cpp as part of
33 | * HelloObject
34 | */
35 |
36 | // add more methods/classes below that youd like to use in Javascript world
37 | // then create a directory in /src with a .cpp and a .hpp file.
38 | // Include your .hpp file at the top of this file.
39 | }
40 |
41 | // Initialize the module (we only do this once)
42 | // Mark this NOLINT to avoid the clang-tidy checks
43 | // NODE_GYP_MODULE_NAME is the name of our module as defined in 'target_name'
44 | // variable in the 'binding.gyp', which is passed along as a compiler define
45 | NODE_API_MODULE(NODE_GYP_MODULE_NAME, init) // NOLINT
46 |
--------------------------------------------------------------------------------
/src/module_utils.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 |
6 | namespace utils {
7 |
8 | /*
9 | * This is an internal function used to return callback error messages instead of
10 | * throwing errors.
11 | * Usage:
12 | *
13 | * return CallbackError(env, "error message", callback);
14 | *
15 | */
16 |
17 | inline Napi::Value CallbackError(Napi::Env env, std::string const& message, Napi::Function const& func)
18 | {
19 | Napi::Object obj = Napi::Object::New(env);
20 | obj.Set("message", message);
21 | return func.Call({obj});
22 | }
23 |
24 | } // namespace utils
25 |
26 | namespace gsl {
27 | template
28 | using owner = T;
29 | } // namespace gsl
30 |
31 | // ^^^ type alias required for clang-tidy (cppcoreguidelines-owning-memory)
32 |
--------------------------------------------------------------------------------
/src/object_async/hello_async.cpp:
--------------------------------------------------------------------------------
1 | #include "hello_async.hpp"
2 | #include "../cpu_intensive_task.hpp"
3 | #include "../module_utils.hpp"
4 |
5 | #include
6 | #include