├── .editorconfig
├── .eslintrc
├── .gitattributes
├── .github
├── CONTRIBUTING.md
├── dependabot.yml
└── workflows
│ ├── ci.yml
│ └── codeql-analysis.yml
├── .gitignore
├── .jsdoc-config-type-def.json
├── .jsdoc-config.json
├── .npmignore
├── .nycrc.js
├── CHANGELOG.yaml
├── LICENSE.md
├── README.md
├── benchmark
└── benchmark-results.json
├── codecov.yml
├── docs
├── concepts.md
├── mutation-tracking.md
└── tutorial-jsdoc-config.json
├── examples
├── collection-v2.json
├── console-readout.js
├── digest.json
├── hawk.json
├── nested-v2-collection-without-name.json
├── nested-v2-collection.json
└── oauth1.json
├── index.js
├── lib
├── collection
│ ├── certificate-list.js
│ ├── certificate.js
│ ├── collection.js
│ ├── cookie-list.js
│ ├── cookie.js
│ ├── description.js
│ ├── event-list.js
│ ├── event.js
│ ├── form-param.js
│ ├── header-list.js
│ ├── header.js
│ ├── item-group.js
│ ├── item.js
│ ├── mutation-tracker.js
│ ├── property-base.js
│ ├── property-list.js
│ ├── property.js
│ ├── proxy-config-list.js
│ ├── proxy-config.js
│ ├── query-param.js
│ ├── request-auth.js
│ ├── request-body.js
│ ├── request.js
│ ├── response.js
│ ├── script.js
│ ├── url.js
│ ├── variable-list.js
│ ├── variable-scope.js
│ ├── variable.js
│ └── version.js
├── content-info
│ └── index.js
├── index.js
├── superstring
│ ├── dynamic-variables.js
│ └── index.js
├── url-pattern
│ ├── url-match-pattern-list.js
│ └── url-match-pattern.js
└── util.js
├── npm
├── build-docs.js
├── build-types.js
├── create-release.js
├── publish-coverage.js
├── test-benchmark.js
├── test-browser.js
├── test-lint.js
├── test-system.js
└── test-unit.js
├── package-lock.json
├── package.json
├── test
├── .eslintrc
├── benchmark
│ └── variable-substitution.bench.js
├── fixtures
│ ├── audio.mp3
│ ├── icon.png
│ ├── index.js
│ ├── japaneseCharacters.txt
│ └── russianCharacters.txt
├── karma.conf.js
├── system
│ ├── jsdoc-config.test.js
│ ├── npm-publish.test.js
│ ├── repository.test.js
│ └── source-modules.test.js
└── unit
│ ├── certificate-list.test.js
│ ├── certificate.test.js
│ ├── collection.test.js
│ ├── content-info.test.js
│ ├── cookie-list.test.js
│ ├── cookie.test.js
│ ├── description.test.js
│ ├── dynamic-variables.test.js
│ ├── event-list.test.js
│ ├── event.test.js
│ ├── form-param.test.js
│ ├── header-list.test.js
│ ├── header.test.js
│ ├── item-group.test.js
│ ├── item.test.js
│ ├── mutation-tracker.test.js
│ ├── property-base.test.js
│ ├── property-list.test.js
│ ├── property.test.js
│ ├── proxy-config-list.test.js
│ ├── proxy-config.test.js
│ ├── query-param.test.js
│ ├── request-auth.test.js
│ ├── request-body.test.js
│ ├── request.test.js
│ ├── response-mime.test.js
│ ├── response.test.js
│ ├── script.test.js
│ ├── superstring.test.js
│ ├── url-match-pattern-list.test.js
│ ├── url-match-pattern.test.js
│ ├── url.test.js
│ ├── util.test.js
│ ├── variable-list.test.js
│ ├── variable-scope.test.js
│ ├── variable.test.js
│ └── version.test.js
└── types
└── index.d.ts
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | max_length = 120
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 |
13 | [*.{json, yml, html, hbs}]
14 | indent_size = 2
15 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default behavior
2 | * text=auto
3 |
4 | # JavaScript files will always have LF line endings
5 | *.js text eol=lf
6 |
7 | # JSON files always have LF line endings
8 | *.json text eol=lf
9 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "npm"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 | day: "saturday"
8 | time: "03:14"
9 | timezone: Asia/Calcutta
10 | rebase-strategy: "disabled"
11 | open-pull-requests-limit: 10
12 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | paths-ignore:
6 | - 'docs/**'
7 | - '*.md'
8 | pull_request:
9 | branches: [$default-branch]
10 | schedule:
11 | - cron: '0 12 * * 0'
12 |
13 | jobs:
14 | lint:
15 | name: Lint
16 | runs-on: ubuntu-latest
17 |
18 | steps:
19 | - name: Checkout repository
20 | uses: actions/checkout@v3
21 |
22 | - name: Use Node.js 18.x
23 | uses: actions/setup-node@v3
24 | with:
25 | node-version: 18.x
26 | cache: 'npm'
27 |
28 | - name: Install
29 | run: npm ci
30 |
31 | - name: Run lint tests
32 | run: npm run test-lint
33 |
34 | browser-tests:
35 | name: Browser Tests
36 | runs-on: ubuntu-latest
37 |
38 | steps:
39 | - name: Checkout repository
40 | uses: actions/checkout@v3
41 |
42 | - name: Use Node.js 18.x
43 | uses: actions/setup-node@v3
44 | with:
45 | node-version: 18.x
46 | cache: 'npm'
47 |
48 | - name: Install
49 | run: npm ci
50 |
51 | - name: Run browser tests
52 | run: npm run test-browser
53 |
54 | tests:
55 | name: Tests
56 | runs-on: ${{ matrix.os }}
57 | strategy:
58 | fail-fast: false
59 | matrix:
60 | node-version: [18, 20]
61 | os: [ubuntu-latest, windows-latest]
62 | include:
63 | - coverage: true
64 | node-version: latest
65 | os: ubuntu-latest
66 |
67 | steps:
68 | - name: Checkout repository
69 | uses: actions/checkout@v3
70 |
71 | - name: Use Node.js ${{ matrix.node-version }}
72 | uses: actions/setup-node@v3
73 | with:
74 | node-version: ${{ matrix.node-version }}
75 | cache: 'npm'
76 |
77 | - name: Install
78 | run: npm ci
79 |
80 | - name: Run system tests
81 | run: npm run test-system
82 |
83 | - name: Run unit tests
84 | run: npm run test-unit
85 |
86 | - if: ${{ matrix.coverage }}
87 | name: Upload coverage
88 | run: npm run codecov -- -c -Z -f .coverage/coverage-final.json -F unit -t ${{ secrets.CODECOV_TOKEN }}
89 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [develop, gh-pages, main]
6 | pull_request:
7 | # The branches below must be a subset of the branches above
8 | branches: [develop]
9 | schedule:
10 | - cron: '0 12 * * 0'
11 |
12 | jobs:
13 | analyze:
14 | name: Analyze
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | # Override automatic language detection by changing the below list
21 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
22 | language: ['javascript']
23 | # Learn more...
24 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
25 |
26 | steps:
27 | - name: Checkout repository
28 | uses: actions/checkout@v2
29 | with:
30 | # We must fetch at least the immediate parents so that if this is
31 | # a pull request then we can checkout the head.
32 | fetch-depth: 2
33 |
34 | # If this run was triggered by a pull request event, then checkout
35 | # the head of the pull request instead of the merge commit.
36 | - run: git checkout HEAD^2
37 | if: ${{ github.event_name == 'pull_request' }}
38 |
39 | # Initializes the CodeQL tools for scanning.
40 | - name: Initialize CodeQL
41 | uses: github/codeql-action/init@v1
42 | with:
43 | languages: ${{ matrix.language }}
44 | # If you wish to specify custom queries, you can do so here or in a config file.
45 | # By default, queries listed here will override any specified in a config file.
46 | # Prefix the list here with "+" to use these queries and those in the config file.
47 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
48 |
49 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
50 | # If this step fails, then you should remove it and run the build manually (see below)
51 | - name: Autobuild
52 | uses: github/codeql-action/autobuild@v1
53 |
54 | # ℹ️ Command-line programs to run using the OS shell.
55 | # 📚 https://git.io/JvXDl
56 |
57 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
58 | # and modify them (or add more) to build your code if your project
59 | # uses a compiled language
60 |
61 | #- run: |
62 | # make bootstrap
63 | # make release
64 |
65 | - name: Perform CodeQL Analysis
66 | uses: github/codeql-action/analyze@v1
67 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # PLATFORM
2 | # ========
3 | # All exclusions that are specific to the NPM, GIT, IDE and Operating Systems.
4 |
5 | # - Do not allow installed node modules to be committed. Doing `npm install -d` will bring them in root or other places.
6 | node_modules
7 |
8 | # - Do not commit any log file from anywhere
9 | *.log
10 | *.log.*
11 |
12 | # - Prevent addition of OS specific file explorer files
13 | Thumbs.db
14 | .DS_Store
15 |
16 | # Prevent IDE stuff
17 | .idea
18 | .vscode
19 |
20 | # PROJECT
21 | # =======
22 | # Configuration pertaining to project specific repository structure.
23 |
24 | # - Prevent Sublime text IDE files from being committed to repository
25 | *.sublime-*
26 |
27 | # - Allow sublime text project file to be committed in the development directory.
28 | !/develop/*.sublime-project
29 |
30 | # - Prevent CI output files from being Added
31 | /out/
32 |
33 | # - Prevent diff backups from SourceTree from showing as commit.
34 | *.BACKUP.*
35 | *.BASE.*
36 | *.LOCAL.*
37 | *.REMOTE.*
38 | *.orig
39 |
40 | # - Prevent unit test coverage reports from being committed to the repository
41 | .coverage
42 | .nyc_output
43 |
--------------------------------------------------------------------------------
/.jsdoc-config-type-def.json:
--------------------------------------------------------------------------------
1 | {
2 | "tags": {
3 | "allowUnknownTags": true,
4 | "dictionaries": [
5 | "jsdoc",
6 | "closure"
7 | ]
8 | },
9 | "source": {
10 | "include": [
11 | "lib"
12 | ],
13 | "includePattern": ".+\\.js(doc)?$",
14 | "excludePattern": "(^|\\/|\\\\)_"
15 | },
16 | "plugins": [
17 | "tsd-jsdoc/dist/plugin"
18 | ],
19 | "templates": {
20 | "cleverLinks": true,
21 | "default": {
22 | "outputSourceFiles": false
23 | }
24 | },
25 | "opts": {
26 | "destination": "./types",
27 | "template": "tsd-jsdoc/dist",
28 | "outFile": "index.d.ts",
29 | "recurse": true
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.jsdoc-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "tags": {
3 | "allowUnknownTags": true,
4 | "dictionaries": ["jsdoc", "closure"]
5 | },
6 | "source": {
7 | "include": [ ],
8 | "includePattern": ".+\\.js(doc)?$",
9 | "excludePattern": "(^|\\/|\\\\)_"
10 | },
11 |
12 | "plugins": [
13 | "plugins/markdown"
14 | ],
15 |
16 | "templates": {
17 | "cleverLinks": false,
18 | "monospaceLinks": false,
19 | "highlightTutorialCode" : true
20 | },
21 |
22 | "opts": {
23 | "template": "./node_modules/postman-jsdoc-theme",
24 | "encoding": "utf8",
25 | "destination": "./out/docs",
26 | "recurse": true,
27 | "readme": "README.md"
28 | },
29 |
30 | "markdown": {
31 | "parser": "gfm",
32 | "hardwrap": false
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # PLATFORM
2 | # ========
3 | # All exclusions that are specific to the NPM, GIT, IDE and Operating Systems.
4 |
5 | # - Do not allow installed node modules to be committed. Doing `npm install -d` will bring them in root or other places.
6 | node_modules
7 |
8 | # - Do not commit any log file from anywhere
9 | *.log
10 | *.log.*
11 |
12 | # - Prevent addition of OS specific file explorer files
13 | Thumbs.db
14 | .DS_Store
15 |
16 | # Prevent IDE stuff
17 | .idea
18 | .vscode
19 |
20 | # PROJECT
21 | # =======
22 | # Configuration pertaining to project specific repository structure.
23 |
24 | # - Prevent Sublime text IDE files from being committed to repository
25 | *.sublime-*
26 |
27 | # - Allow sublime text project file to be committed in the development directory.
28 | !/develop/*.sublime-project
29 |
30 | # - Prevent CI output files from being added
31 | /out/
32 |
33 | # - Prevent diff backups from SourceTree from showing as commit.
34 | *.BACKUP.*
35 | *.BASE.*
36 | *.LOCAL.*
37 | *.REMOTE.*
38 | *.orig
39 |
40 | # - Prevent code coverage reports from being added
41 | .coverage
42 | .nyc_output
43 |
44 | # - Prevent config and test files from being added
45 | .git*
46 | npm/
47 | test/
48 | docs/
49 | examples/
50 | benchmark/
51 | .eslintrc
52 | .nycrc.js
53 | codecov.yml
54 | .editorconfig
55 | .jsdoc-config.json
56 | .jsdoc-config-type-def.json
57 |
--------------------------------------------------------------------------------
/.nycrc.js:
--------------------------------------------------------------------------------
1 | const TEST_TYPE = ((argv) => {
2 | let match = argv[argv.length - 1].match(/npm\/test-(\w+).js/);
3 |
4 | return match && match[1] || '';
5 | })(process.argv);
6 |
7 | function configOverrides(testType) {
8 | switch (testType) {
9 | case 'unit':
10 | return {
11 | statements: 100,
12 | branches: 100,
13 | functions: 100,
14 | lines: 100
15 | };
16 | default:
17 | return {}
18 | }
19 | }
20 |
21 | module.exports = {
22 | all: true,
23 | 'check-coverage': true,
24 | 'report-dir': '.coverage',
25 | 'temp-dir': '.nyc_output',
26 | include: ['lib/**/*.js'],
27 | reporter: ['lcov', 'json', 'text', 'text-summary'],
28 | ...configOverrides(TEST_TYPE),
29 | };
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Postman Collection SDK [](https://github.com/postmanlabs/postman-collection/actions/workflows/ci.yml) [](https://codecov.io/gh/postmanlabs/postman-collection)
2 |
3 | Postman Collection SDK is a NodeJS module that allows a developer to work with Postman Collections. Using this module a
4 | developer can create collections, manipulate them and then export them in a format that the Postman Apps and Postman CLI
5 | Runtimes (such as [Newman](https://github.com/postmanlabs/newman)) can consume.
6 |
7 | A collection lets you group individual requests together. These requests can be further organized into folders to
8 | accurately mirror your API. Requests can also store sample responses when saved in a collection. You can add metadata
9 | like name and description too so that all the information that a developer needs to use your API is available easily.
10 |
11 | To know more about Postman Collections, visit the
12 | [collection documentation section on Postman Website](https://postman.com/collection/).
13 |
14 | > The new [Collection Format v2](https://blog.postman.com/travelogue-of-postman-collection-format-v2/)
15 | > builds a stronger foundation for improving your productivity while working with APIs. We want your feedback and iron
16 | > out issues before this goes into the Postman Apps.
17 |
18 | ## Installing the SDK
19 |
20 | Postman Collection SDK can be installed using NPM or directly from the git repository within your NodeJS projects. If
21 | installing from NPM, the following command installs the SDK and saves in your `package.json`
22 |
23 | ```terminal
24 | > npm install postman-collection --save
25 | ```
26 |
27 |
28 | ## Getting Started
29 |
30 | In this example snippet we will get started by loading a collection from a file and output the same in console.
31 |
32 | ```javascript
33 | var fs = require('fs'), // needed to read JSON file from disk
34 | Collection = require('postman-collection').Collection,
35 | myCollection;
36 |
37 | // Load a collection to memory from a JSON file on disk (say, sample-collection.json)
38 | myCollection = new Collection(JSON.parse(fs.readFileSync('sample-collection.json').toString()));
39 |
40 | // log items at root level of the collection
41 | console.log(myCollection.toJSON());
42 | ```
43 |
44 | After loading the collection from file, one can do a lot more using the functions that are available in the SDK. To know
45 | more about these functions, head over to
46 | [Collection SDK Docs](http://www.postmanlabs.com/postman-collection).
47 |
48 | ## Postman Collection Schema
49 |
50 | The collection schema outlines the JSON definition of data structure accepted by the constructor of each properties of
51 | this SDK. In other words, this SDK provides JavaScript level object manipulation for the JSON structure defined by
52 | Postman Collection Format in [http://schema.postman.com/](http://schema.postman.com/).
53 |
54 | | Schema Version | Compatible SDK Versions |
55 | |----------------|-------------------------|
56 | | 1.0 | none |
57 | | 2.0 | <3.0 |
58 | | 2.1 | >= 3.0 |
59 |
60 | Conceptually, a JSON input to the constructor of an SDK property should provide similar output when that property
61 | instance's `.toJSON()` is called.
62 |
--------------------------------------------------------------------------------
/benchmark/benchmark-results.json:
--------------------------------------------------------------------------------
1 | {
2 | "suites": [
3 | {
4 | "name": "SuperString variable substitution",
5 | "scenarios": [
6 | {
7 | "name": "single constant dynamic variable",
8 | "executions": 411989,
9 | "time": 12136.21698637585,
10 | "error": 2.9153562603877248
11 | },
12 | {
13 | "name": "two constant dynamic variables",
14 | "executions": 223254,
15 | "time": 22395.94219588451,
16 | "error": 0.5184261312204904
17 | },
18 | {
19 | "name": "four constant dynamic variables",
20 | "executions": 96120,
21 | "time": 52018.067613399915,
22 | "error": 0.7425831865647227
23 | },
24 | {
25 | "name": "eight constant dynamic variables",
26 | "executions": 73825,
27 | "time": 67727.10917710802,
28 | "error": 0.6059831169932062
29 | },
30 | {
31 | "name": "sixteen constant dynamic variables",
32 | "executions": 59716,
33 | "time": 83729.05474244758,
34 | "error": 0.8958354666864753
35 | },
36 | {
37 | "name": "thirty-two constant dynamic variables",
38 | "executions": 19165,
39 | "time": 260888.65687451084,
40 | "error": 0.6319144162829673
41 | },
42 | {
43 | "name": "sixty-four constant dynamic variables",
44 | "executions": 8866,
45 | "time": 563898.6565531243,
46 | "error": 68.6127576990454
47 | }
48 | ]
49 | }
50 | ]
51 | }
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | range: 70..100 # green if 100+, red if 70-
3 |
4 | status:
5 | patch:
6 | # coverage status for pull request diff
7 | default:
8 | target: 100 # any patch should be 100% covered
9 | threshold: 1% # allow a little drop
10 |
11 | project:
12 | # coverage status for whole project
13 | default:
14 | target: auto # use coverage of base commit as target
15 | threshold: 1% # allow a little drop
16 |
17 | # coverage status for unit tests
18 | unit:
19 | target: 100
20 | flags:
21 | - unit
22 |
23 | parsers:
24 | javascript:
25 | enable_partials: yes # use partial line coverage
26 |
--------------------------------------------------------------------------------
/docs/concepts.md:
--------------------------------------------------------------------------------
1 | # Concepts
2 |
3 | This is a gentle introduction to the sort of functionality that the SDK provides.
4 |
5 | ## Collection Hierarchy
6 | At a very high level, Collections are organized in the following way:
7 | ```
8 |
9 | +------------+
10 | +--------------------------+ Collection +------------------------+
11 | | +------+-----+ |
12 | | | |
13 | | | |
14 | +-------v---------+ +--v---+ +-----v-----+
15 | |ItemGroup(Folder)| +----------+ Item +------------+ |Information|
16 | +-+-----------+---+ | +---+--+ | +-----------+
17 | | | | | |
18 | +--------v--+ +---v--+ +----v----+ +----v------+ +---v----+
19 | | ItemGroup | | Item | | Request | | Responses | | Events |
20 | +-----------+ +------+ +---------+ +-----------+ +--------+
21 | ```
22 |
23 | ### Collection
24 |
25 | A collection can contain a number of `Item`s, `ItemGroup`s and can have a single
26 | information block.
27 |
28 | E.g: **A very simple Collection**
29 | ```json
30 | {
31 | "information": {
32 | "name": "My Collection",
33 | "version": "v2.0.0",
34 | "description": "This is a demo collection.",
35 | "schema": "https://schema.getpostman.com/json/collection/v2.0.0/"
36 | },
37 | "item": []
38 | }
39 | ```
40 |
41 | The "schema" property is required, and must be set to the proper URL as above.
42 | The "item" array contains Folders (ItemGroups) or Items.
43 |
44 | ### Item
45 | An Item is the basic building block for a collection. It represents an HTTP request,
46 | along with the associated metadata.
47 |
48 | E.g: **A simple Item**
49 | ```json
50 | {
51 | "id": "my-first-item",
52 | "name": "My First Item",
53 | "description": "This is an Item that contains a single HTTP GET request. It doesn't really do much yet!",
54 | "request": "http://echo.getpostman.com/get",
55 | "response": []
56 | }
57 | ```
58 |
59 | An Item can have multiple saved responses, which are stored in the `response` array. Response is further elaborated below.
60 | While we've defined a very simple request above, it can become really complicated, as you'll soon see!
61 |
62 | ### ItemGroup (Folder)
63 | An ItemGroup is a simple container for Items. Literally, a Collection is just an ItemGroup with a special
64 | `information` block.
65 |
66 | E.g: **An ItemGroup with two Items**
67 | ```json
68 | {
69 | "id": "my-first-itemgroup",
70 | "name": "First Folder",
71 | "description": "This ItemGroup (Folder) contains two Items.",
72 | "item": [
73 | {
74 | "id": "1",
75 | "name": "Item A",
76 | "request": "http://echo.getpostman.com/get"
77 | },
78 | {
79 | "id": "2",
80 | "name": "Item B",
81 | "request": "http://echo.getpostman.com/headers"
82 | }
83 | ]
84 | }
85 | ```
86 | The `item` array above contains the Items in this ItemGroup.
87 |
88 | ### Request
89 | A Request represents an HTTP request. Usually, a Request belongs to an Item. Requests can be specified as a string
90 | (check the example above) or as a JSON Object. If specified as a string, it is assumed to be a GET request.
91 |
92 | E.g: **A mildly complicated Request**
93 | ```json
94 | {
95 | "description": "This is a sample POST request",
96 | "url": "https://echo.getpostman.com/post",
97 | "method": "POST",
98 | "header": [
99 | {
100 | "key": "Content-Type",
101 | "value": "application/json"
102 | },
103 | {
104 | "key": "Host",
105 | "value": "echo.getpostman.com"
106 | }
107 | ],
108 | "body": {
109 | "mode": "urlencoded",
110 | "urlencoded": [
111 | {
112 | "key": "my-body-variable",
113 | "value": "Something Awesome!"
114 | }
115 | ]
116 | }
117 | }
118 | ```
119 | For more on request bodies, check the API documentation: {@link RequestBody}
120 |
121 | E.g: **A simple request with Authentication information**
122 | ```json
123 | {
124 | "url": "https://echo.getpostman.com/basic-auth",
125 | "method": "GET",
126 | "auth": {
127 | "type": "basic",
128 | "basic": {
129 | "username": "fred",
130 | "password": "hunter2"
131 | }
132 | }
133 | }
134 | ```
135 | The SDK supports a number of auth types, refer to the API documentation: {@link RequestAuth}
136 |
137 | ### Events
138 |
139 | The SDK currently supports two events:
140 |
141 | 1. Test Script: `test`
142 | You can associate a test script with an Item. The test script is usually executed _after_ the actual HTTP request is
143 | sent, and the response is received.
144 |
145 | 2. Pre-Request Script: `prerequest`
146 | Pre-Request scripts are usually executed _before_ the HTTP request is sent.
147 |
148 | E.g: **An Item with Events**
149 | ```json
150 | {
151 | "id": "evented-item",
152 | "name": "Item with Events",
153 | "description": "This is an Item that contains `test and `prerequest` events.",
154 | "request": "http://echo.getpostman.com/get",
155 | "event": [
156 | {
157 | "listen": "prerequest",
158 | "script": {
159 | "type": "text/javascript",
160 | "exec": "console.log('We are in the pre-request script, the request has not run yet!')"
161 | }
162 | },
163 | {
164 | "listen": "test",
165 | "script": {
166 | "type": "text/javascript",
167 | "exec": "console.log('We are using the test script now, and the request was already sent!')"
168 | }
169 | }
170 | ]
171 | }
172 | ```
173 |
--------------------------------------------------------------------------------
/docs/mutation-tracking.md:
--------------------------------------------------------------------------------
1 | ### Introduction
2 |
3 | A mutation represents a change to the state of an object. To track a mutation would mean to capture the transition from
4 | one state to another. This means capturing the state transition as a serializeable object that can be transported and
5 | reapplied on an different object. Once captured the same mutation when applied on two separate objects with same initial
6 | state should transition them to the same final state.
7 |
8 | ### When would you need need to track mutations?
9 |
10 | Let's take executing collection scripts in `postman-sandbox` for example. Let's say you pass down an environment and a
11 | script that updates your environment, to the sandbox to execute. Once the script finishes executing you would get the
12 | final state of the environment after the updates. Now you have the final state of the environment. But you do not know
13 | what updates the script did to your environment. Also you do not know all the intermediate states of the environment
14 | when the script was executing.
15 |
16 | Now imagine you could track every change to the environment and get it at the end of script execution. You can replay
17 | them again from an initial state, pause at any point and continue. Mutation tracking can help you with that.
18 |
19 | You would typically want to track mutations when you want to track individual changes to an object and store/transport
20 | them. You might also need mutation tracking when you want to observe changes on an object and replay them on a different
21 | object to achieve mirroring.
22 |
23 | ### Basic Components
24 |
25 | * **Mutation**: The basic component of mutation tracking system is an individual mutation. This captures a single change.
26 | A mutation is serializeable and can be applied to any object of the similar type.
27 | * **MutationTracker**: Mutation tracker collects a sequence of mutations and provides helpers to work with mutations, like
28 | applying them on a new object. The mutation tracker can also optimize the sequence of mutations, like compressing them.
29 |
30 | ## Representing a mutation
31 |
32 | Every mutation has four parts
33 |
34 | * **Target** - The origin of the mutation
35 | * **Key Path** - Path to the property of the target that got mutated
36 | * **Instruction** - The nature of mutation
37 | * **Value (Optional)** - The payload for the instruction
38 |
39 | To capture all the information in an optimized format we use a serialization spec based on - JSON Delta (http://json-delta.readthedocs.io/en/latest/)
40 |
41 | An example `set` operation would look like - `['foo', 1]`
42 |
43 | If we break this down
44 |
45 | ```
46 | sample.mutations = [['foo', 1]]
47 | | |___|_______ Key Path
48 | | |_______ Value
49 | |_________________________________ Target
50 | ```
51 |
52 | You would have noticed that the instruction is not explicitly captured. That's because it is derived from the parameter set.
53 |
54 | For example an unset operation would look like `['foo']`.
55 |
56 | Which means you can derive the instruction based on the shape of the mutation itself. A mutation with single parameter
57 | would imply an unset operation. A mutation with two parameters would imply a set operation.
58 |
59 | ### Mutation tracking in Variable Scopes
60 |
61 | To track mutations in a Postman Variable Scope, you can enabled it like
62 |
63 | ```js
64 | var VariableScope = require('postman-collection').VariableScope,
65 | environment = new VariableScope();
66 |
67 | // enables tracking mutations
68 | environment.enableTracking();
69 | ```
70 |
71 | From this point onwards any `set/unset/clear` operations on `environment` will be captured in in `environment.mutations`.
72 |
73 | You can then apply the same mutation on a different object like
74 |
75 | ```js
76 | var environmentCopy = new VariableScope();
77 |
78 | // applies the mutations captured on `environment` into `environmentCopy` making it a mirror
79 | environment.mutations.applyOn(environmentCopy);
80 | ```
81 |
82 | ### Limitations and scope for extension
83 |
84 | Postman collection SDK supports tracking mutations on `VariableScopes`. We could apply the same concepts to any type
85 | of object not restricted to a `VariableScope`.
86 |
87 | In practise more complex types would have complex instructions that are not restricted to `set/unset`. To capture those
88 | we might have to extend our representation for a mutation to support more complex instructions.
89 |
90 | We will have to capture the instruction explicitly in that case. To do so we can think of something like
91 |
92 | ```
93 | ['id', 'addRequest', '#', '1', 'request1']
94 | |________|_________|____|________|___________ Mutation Id
95 | |_________|____|________|___________ Instruction
96 | |____|________|___________ Delimiter to differentiate from first generation mutations
97 | |________|___________ Key Path
98 | |___________ Value
99 | ```
--------------------------------------------------------------------------------
/docs/tutorial-jsdoc-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "concepts": {
3 | "title": "Postman SDK Concepts"
4 | },
5 | "mutation-tracking": {
6 | "title": "Tracking Variable Mutations"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/examples/console-readout.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs'),
2 | stripJSONComments = require('strip-json-comments'),
3 | Collection = require('../lib/index').Collection;
4 |
5 | fs.readFile(process.argv.slice(2).pop(), 'utf8', function (err, data) {
6 | if (err) {
7 | throw err;
8 | }
9 |
10 | try {
11 | data = new Collection(JSON.parse(stripJSONComments(data)));
12 | }
13 | catch (e) {
14 | throw e;
15 | }
16 |
17 | console.dir(data, { colors: true, depth: 10000 });
18 | });
19 |
--------------------------------------------------------------------------------
/examples/digest.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": [],
3 | "info": {
4 | "name": "Echo - Digest",
5 | "_postman_id": "10084d91-feb7-91f8-cea3-8432b25502e4",
6 | "description": "Postman Echo is service you can use to test your REST clients and make sample API calls. It provides endpoints for `GET`, `POST`, `PUT`, various auth mechanisms and other utility endpoints.",
7 | "schema": "http://schema.getpostman.com/collection/v2/collection.json"
8 | },
9 | "item": [
10 | {
11 | "name": "Auth: Digest",
12 | "description": "Digest authentication protects an endpoint with a username and password without actually transmitting the password over network.\nOne has to apply a hash function (like MD5, etc) to the username and password before sending them over the network.\n\n> Username: `postman`\n>\n> Password: `password`\n\nUnlike Basic-Auth, authentication happens using two consecutive requests where the first request returns `401 Unauthorised` along with `WWW-Authenticate` header containing information that needs to be used to authenticate subsequent calls.\n\nTo know more about digest authentication, refer to the [Digest Access Authentication](https://en.wikipedia.org/wiki/Digest_access_authentication) wikipedia article.\nThe article on [authentication helpers](https://www.getpostman.com/docs/helpers#digest-auth) elaborates how to use the same within the Postman app.",
13 | "item": [
14 | {
15 | "id": "9808ab99-bb91-6d83-13e4-0219c2377e35",
16 | "name": "DigestAuth Request",
17 | "event": [
18 | {
19 | "listen": "test",
20 | "script": {
21 | "type": "text/javascript",
22 | "exec": "tests[\"response code is 401\"] = responseCode.code === 401;\ntests[\"response has WWW-Authenticate header\"] = (postman.getResponseHeader('WWW-Authenticate'));\n\nvar authenticateHeader = postman.getResponseHeader('WWW-Authenticate'),\n realmStart = authenticateHeader.indexOf('\"',authenticateHeader.indexOf(\"realm\")) + 1 ,\n realmEnd = authenticateHeader.indexOf('\"',realmStart),\n realm = authenticateHeader.slice(realmStart,realmEnd),\n nonceStart = authenticateHeader.indexOf('\"',authenticateHeader.indexOf(\"nonce\")) + 1,\n nonceEnd = authenticateHeader.indexOf('\"',nonceStart),\n nonce = authenticateHeader.slice(nonceStart,nonceEnd);\n \npostman.setGlobalVariable('echo_digest_realm', realm);\npostman.setGlobalVariable('echo_digest_nonce', nonce);"
23 | }
24 | }
25 | ],
26 | "request": {
27 | "auth": {
28 | "type": "noauth",
29 | "noauth": {}
30 | },
31 | "url": "https://echo.getpostman.com/digest-auth",
32 | "method": "GET",
33 | "header": "Content-Type: application/json\nAuthorization: Hawk id=\"dh37fgj492je\", ts=\"1448549987\", nonce=\"eOJZCd\", mac=\"O2TFlvAlMvKVSKOzc6XkfU6+5285k5p3m5dAjxumo2k=\"\n",
34 | "body": {
35 | "mode": "formdata",
36 | "formdata": [
37 | {
38 | "key": "code",
39 | "value": "xWnkliVQJURqB2x1",
40 | "type": "text",
41 | "enabled": true
42 | },
43 | {
44 | "key": "grant_type",
45 | "value": "authorization_code",
46 | "type": "text",
47 | "enabled": true
48 | },
49 | {
50 | "key": "redirect_uri",
51 | "value": "https://www.getpostman.com/oauth2/callback",
52 | "type": "text",
53 | "enabled": true
54 | },
55 | {
56 | "key": "client_id",
57 | "value": "abc123",
58 | "type": "text",
59 | "enabled": true
60 | },
61 | {
62 | "key": "client_secret",
63 | "value": "ssh-secret",
64 | "type": "text",
65 | "enabled": true
66 | }
67 | ]
68 | },
69 | "description": "Performing a simple `GET` request to this endpoint returns status code `401 Unauthorized` with `WWW-Authenticate` header containing information to successfully authenticate subsequent requests.\nThe `WWW-Authenticate` header must be processed to extract `realm` and `nonce` values to hash subsequent requests.\n\nWhen this request is executed within Postman, the script attached with this request does the hard work of extracting realm and nonce from the header and set it as [global variables](https://www.getpostman.com/docs/environments#global-variables) named `echo_digest_nonce` and `echo_digest_realm`.\nThese variables are re-used in subsequent request for seamless integration of the two requests."
70 | },
71 | "response": [
72 | {
73 | "name": "a sample response",
74 | "originalRequest": "http://echo.getpostman.com/status/200",
75 | "status": "200 OK",
76 | "code": 200,
77 | "header": "Content-Type: application/json\nAuthorization: Hawk id=\"dh37fgj492je\", ts=\"1448549987\", nonce=\"eOJZCd\", mac=\"O2TFlvAlMvKVSKOzc6XkfU6+5285k5p3m5dAjxumo2k=\"\n",
78 | "cookie": [
79 | {
80 | "domain": ".httpbin.org",
81 | "expires": 1502442248,
82 | "hostOnly": false,
83 | "httpOnly": false,
84 | "name": "_ga",
85 | "path": "/",
86 | "secure": false,
87 | "session": false,
88 | "_postman_storeId": "0",
89 | "value": "GA1.2.113558537.1435817423"
90 | }
91 | ],
92 | "body": "response body"
93 | }
94 | ]
95 | },
96 | {
97 | "id": "ee34b510-6e68-1280-1160-bc57bc29436e",
98 | "name": "DigestAuth Success",
99 | "event": [
100 | {
101 | "listen": "test",
102 | "script": {
103 | "type": "text/javascript",
104 | "exec": "tests[\"response code is 200\"] = responseCode.code === 200;\ntests[\"body contains authenticated\"] = responseBody.has(\"authenticated\");"
105 | }
106 | }
107 | ],
108 | "request": {
109 | "auth": {
110 | "type": "digest",
111 | "digest": {
112 | "algorithm": "MD5",
113 | "username": "postman",
114 | "realm": "{{echo_digest_realm}}",
115 | "password": "password",
116 | "nonce": "{{echo_digest_nonce}}",
117 | "nonceCount": "",
118 | "clientNonce": "",
119 | "opaque": "",
120 | "qop": ""
121 | }
122 | },
123 | "url": "https://echo.getpostman.com/digest-auth",
124 | "method": "GET",
125 | "header": [
126 | {
127 | "key": "Authorization",
128 | "value": "Digest username=\"postman\", realm=\"Users\", nonce=\"ZKMCeJ68NEK1mpeg0i6RMXX7U8qANc9g\", uri=\"/digest-auth\", response=\"5cf1155abf5172ea751daec57db07340\", opaque=\"\"",
129 | "description": ""
130 | }
131 | ],
132 | "body": {
133 | "mode": "formdata",
134 | "formdata": []
135 | },
136 | "description": "This endpoint sends a hashed Digest Authorization header to gain access to a valid `200 Ok` response code. In Postman, it uses the stored [global variables](https://www.getpostman.com/docs/environments#gloval-variables), `echo_digest_realm` and `echo_digest_nonce`, to generate the hashed authorisation header.\n\nWithin Postman, for this request to successfully authenticate, running the previous request \"DigestAuth Request\" stores the relevant information within the global variables."
137 | }
138 | }
139 | ]
140 | }
141 | ]
142 | }
143 |
--------------------------------------------------------------------------------
/examples/hawk.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": [],
3 | "info": {
4 | "name": "hawkAuthTest",
5 | "_postman_id": "d497d10e-e280-8c83-709a-a4d4ea12ad14",
6 | "description": "",
7 | "schema": "http://schema.getpostman.com/collection/v2/collection.json"
8 | },
9 | "item": [
10 | {
11 | "id": "951fc3e8-c6b6-5c19-9f69-4e7499b3127f",
12 | "name": "test hawk auth success",
13 | "request": {
14 | "auth": {
15 | "type": "hawk",
16 | "hawk": {
17 | "authId": "dh37fgj492je",
18 | "authKey": "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn",
19 | "algorithm": "sha256",
20 | "user": "asda",
21 | "saveHelperData": true,
22 | "nonce": "eFRP2o",
23 | "extraData": "skjdfklsjhdflkjhsdf",
24 | "appId": "",
25 | "delegation": "",
26 | "timestamp": ""
27 | }
28 | },
29 | "url": "http://echo.getpostman.com/auth/hawk",
30 | "method": "GET",
31 | "header": [
32 | {
33 | "key": "Authorization",
34 | "value": "Hawk id=\"dh37fgj492je\", ts=\"1448888081\", nonce=\"HoH6Ay\", ext=\"skjdfklsjhdflkjhsdf\", mac=\"moWleO5f/8QbvIiy7oo2zj1bmezhrYwrCkz4BsXg0M4=\"",
35 | "description": ""
36 | }
37 | ],
38 | "body": {
39 | "mode": "formdata",
40 | "formdata": []
41 | },
42 | "description": ""
43 | },
44 | "response": []
45 | }
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/examples/nested-v2-collection-without-name.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": [],
3 | "info": {
4 | "_postman_id": "e5f2e9cf-173b-c60a-7336-ac804a87d762",
5 | "description": "A simple V2 collection to test out multi level folder flows",
6 | "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"
7 | },
8 | "item": [
9 | {
10 | "id": "F1-id",
11 | "description": "",
12 | "item": [
13 | {
14 | "event": [
15 | {
16 | "listen": "test",
17 | "script": {
18 | "type": "text/javascript",
19 | "exec": [
20 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
21 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === 0;"
22 | ]
23 | }
24 | }
25 | ],
26 | "request": {
27 | "url": "https://postman-echo.com/get",
28 | "method": "GET",
29 | "header": [],
30 | "body": {},
31 | "description": ""
32 | },
33 | "response": [],
34 | "id": "F1.R1-id"
35 | },
36 | {
37 | "event": [
38 | {
39 | "listen": "test",
40 | "script": {
41 | "type": "text/javascript",
42 | "exec": [
43 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
44 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === \"1\";"
45 | ]
46 | }
47 | }
48 | ],
49 | "request": {
50 | "url": "https://postman-echo.com/get",
51 | "method": "GET",
52 | "header": [],
53 | "body": {},
54 | "description": ""
55 | },
56 | "response": [],
57 | "id": "F1.R2-id"
58 | },
59 | {
60 | "event": [
61 | {
62 | "listen": "test",
63 | "script": {
64 | "type": "text/javascript",
65 | "exec": [
66 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
67 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === \"2\";"
68 | ]
69 | }
70 | }
71 | ],
72 | "request": {
73 | "url": "https://postman-echo.com/get",
74 | "method": "GET",
75 | "header": [],
76 | "body": {},
77 | "description": ""
78 | },
79 | "response": [],
80 | "id": "F1.R3-id"
81 | }
82 | ]
83 | },
84 | {
85 | "id": "F2-id",
86 | "description": "",
87 | "item": [
88 | {
89 | "id": "F2.F3-id",
90 | "description": "",
91 | "item": [
92 | {
93 | "id": "F2.F3.R1-id",
94 | "event": [
95 | {
96 | "listen": "prerequest",
97 | "script": {
98 | "type": "text/javascript",
99 | "exec": [
100 | "var count = parseInt(postman.getEnvironmentVariable(\"count\"));",
101 | "postman.setEnvironmentVariable(\"count\", isNaN(count) ? 0 : count + 1);"
102 | ]
103 | }
104 | },
105 | {
106 | "listen": "test",
107 | "script": {
108 | "type": "text/javascript",
109 | "exec": [
110 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
111 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === \"3\";"
112 | ]
113 | }
114 | }
115 | ],
116 | "request": {
117 | "url": "https://postman-echo.com/get",
118 | "method": "GET",
119 | "header": [],
120 | "body": {},
121 | "description": ""
122 | },
123 | "response": []
124 | }
125 | ]
126 | },
127 | {
128 | "description": "",
129 | "item": []
130 | },
131 | {
132 | "event": [
133 | {
134 | "listen": "test",
135 | "script": {
136 | "type": "text/javascript",
137 | "exec": [
138 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
139 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === \"4\";"
140 | ]
141 | }
142 | }
143 | ],
144 | "request": {
145 | "url": "https://postman-echo.com/get",
146 | "method": "GET",
147 | "header": [],
148 | "body": {},
149 | "description": ""
150 | },
151 | "response": []
152 | }
153 | ]
154 | },
155 | {
156 | "event": [
157 | {
158 | "listen": "prerequest",
159 | "script": {
160 | "type": "text/javascript",
161 | "exec": [
162 | "var count = parseInt(postman.getEnvironmentVariable(\"count\"));",
163 | "postman.setEnvironmentVariable(\"count\", isNaN(count) ? 0 : count + 1);"
164 | ]
165 | }
166 | },
167 | {
168 | "listen": "test",
169 | "script": {
170 | "type": "text/javascript",
171 | "exec": [
172 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
173 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === \"5\";"
174 | ]
175 | }
176 | }
177 | ],
178 | "request": {
179 | "url": "https://postman-echo.com/get",
180 | "method": "GET",
181 | "header": [],
182 | "body": {},
183 | "description": ""
184 | },
185 | "response": [],
186 | "id": "R1-id"
187 | }
188 | ]
189 | }
190 |
--------------------------------------------------------------------------------
/examples/nested-v2-collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": [],
3 | "info": {
4 | "name": "multi-level-folders-v2",
5 | "_postman_id": "e5f2e9cf-173b-c60a-7336-ac804a87d762",
6 | "description": "A simple V2 collection to test out multi level folder flows",
7 | "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"
8 | },
9 | "item": [
10 | {
11 | "name": "F1",
12 | "id": "F1-id",
13 | "description": "",
14 | "item": [
15 | {
16 | "name": "F1.R1",
17 | "event": [
18 | {
19 | "listen": "test",
20 | "script": {
21 | "type": "text/javascript",
22 | "exec": [
23 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
24 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === 0;"
25 | ]
26 | }
27 | }
28 | ],
29 | "request": {
30 | "url": "https://postman-echo.com/get",
31 | "method": "GET",
32 | "header": [],
33 | "body": {},
34 | "description": ""
35 | },
36 | "response": [],
37 | "id": "F1.R1-id"
38 | },
39 | {
40 | "name": "F1.R2",
41 | "event": [
42 |
43 | {
44 | "listen": "test",
45 | "script": {
46 | "type": "text/javascript",
47 | "exec": [
48 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
49 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === \"1\";"
50 | ]
51 | }
52 | }
53 | ],
54 | "request": {
55 | "url": "https://postman-echo.com/get",
56 | "method": "GET",
57 | "header": [],
58 | "body": {},
59 | "description": ""
60 | },
61 | "response": [],
62 | "id": "F1.R2-id"
63 | },
64 | {
65 | "name": "F1.R3",
66 | "event": [
67 | {
68 | "listen": "test",
69 | "script": {
70 | "type": "text/javascript",
71 | "exec": [
72 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
73 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === \"2\";"
74 | ]
75 | }
76 | }
77 | ],
78 | "request": {
79 | "url": "https://postman-echo.com/get",
80 | "method": "GET",
81 | "header": [],
82 | "body": {},
83 | "description": ""
84 | },
85 | "response": []
86 | }
87 | ]
88 | },
89 | {
90 | "name": "F2",
91 | "id": "F2-id",
92 | "description": "",
93 | "item": [
94 | {
95 | "name": "F2.F3",
96 | "id": "F2.F3-id",
97 | "description": "",
98 | "item": [
99 | {
100 | "name": "F2.F3.R1",
101 | "id": "F2.F3.R1-id",
102 | "event": [
103 | {
104 | "listen": "prerequest",
105 | "script": {
106 | "type": "text/javascript",
107 | "exec": [
108 | "var count = parseInt(postman.getEnvironmentVariable(\"count\"));",
109 | "postman.setEnvironmentVariable(\"count\", isNaN(count) ? 0 : count + 1);"
110 | ]
111 | }
112 | },
113 | {
114 | "listen": "test",
115 | "script": {
116 | "type": "text/javascript",
117 | "exec": [
118 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
119 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === \"3\";"
120 | ]
121 | }
122 | }
123 | ],
124 | "request": {
125 | "url": "https://postman-echo.com/get",
126 | "method": "GET",
127 | "header": [],
128 | "body": {},
129 | "description": ""
130 | },
131 | "response": []
132 | }
133 | ]
134 | },
135 | {
136 | "name": "F4",
137 | "description": "",
138 | "item": []
139 | },
140 | {
141 | "name": "F2.R1",
142 | "event": [
143 | {
144 | "listen": "test",
145 | "script": {
146 | "type": "text/javascript",
147 | "exec": [
148 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
149 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === \"4\";"
150 | ]
151 | }
152 | }
153 | ],
154 | "request": {
155 | "url": "https://postman-echo.com/get",
156 | "method": "GET",
157 | "header": [],
158 | "body": {},
159 | "description": ""
160 | },
161 | "response": []
162 | }
163 | ]
164 | },
165 | {
166 | "name": "R1",
167 | "event": [
168 | {
169 | "listen": "prerequest",
170 | "script": {
171 | "type": "text/javascript",
172 | "exec": [
173 | "var count = parseInt(postman.getEnvironmentVariable(\"count\"));",
174 | "postman.setEnvironmentVariable(\"count\", isNaN(count) ? 0 : count + 1);"
175 | ]
176 | }
177 | },
178 | {
179 | "listen": "test",
180 | "script": {
181 | "type": "text/javascript",
182 | "exec": [
183 | "tests[\"Status code is 200\"] = responseCode.code === 200;",
184 | "tests[\"Request executed in correct order\"] = postman.getEnvironmentVariable(\"count\") === \"5\";"
185 | ]
186 | }
187 | }
188 | ],
189 | "request": {
190 | "url": "https://postman-echo.com/get",
191 | "method": "GET",
192 | "header": [],
193 | "body": {},
194 | "description": ""
195 | },
196 | "response": [],
197 | "id": "R1-id"
198 | }
199 | ]
200 | }
201 |
--------------------------------------------------------------------------------
/examples/oauth1.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": [],
3 | "info": {
4 | "name": "Echo - OAuth 1",
5 | "_postman_id": "5c5fd0ab-84e3-64f2-b08b-f97f1f2337ae",
6 | "description": "Postman Echo is service you can use to test your REST clients and make sample API calls. It provides endpoints for `GET`, `POST`, `PUT`, various auth mechanisms and other utility endpoints.",
7 | "schema": "http://schema.getpostman.com/collection/v2/collection.json"
8 | },
9 | "item": [
10 | {
11 | "id": "e574612b-c19a-66e7-9685-27751bafca0d",
12 | "name": "OAuth1.0 Verify Signature",
13 | "event": [
14 | {
15 | "listen": "test",
16 | "script": {
17 | "type": "text/javascript",
18 | "exec": "tests[\"response code is 200\"] = responseCode.code === 200;\nvar body = JSON.parse(responseBody);\ntests[\"Body contains status pass\"] = body[\"status\"] == \"pass\""
19 | }
20 | }
21 | ],
22 | "request": {
23 | "auth": {
24 | "type": "oauth1",
25 | "oauth1": {
26 | "consumerKey": "RKCGzna7bv9YD57c",
27 | "consumerSecret": "D+EdQ-gs$-%@2Nu7",
28 | "token": "",
29 | "tokenSecret": "",
30 | "signatureMethod": "HMAC-SHA1",
31 | "timestamp": "1453890475",
32 | "nonce": "yly1UR",
33 | "version": "1.0",
34 | "realm": "",
35 | "addParamsToHeader": true,
36 | "autoAddParam": true,
37 | "addEmptyParamsToSign": false
38 | }
39 | },
40 | "url": "https://echo.getpostman.com/oauth1",
41 | "method": "GET",
42 | "header": [
43 | {
44 | "key": "Authorization",
45 | "value": "OAuth oauth_consumer_key=\"RKCGzna7bv9YD57c\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1453890449\",oauth_nonce=\"aT8kIM\",oauth_version=\"1.0\",oauth_signature=\"Ng8eD0bKh6LO5V0A9O6Z%2BY6D0tU%3D\"",
46 | "description": ""
47 | }
48 | ],
49 | "body": {
50 | "mode": "formdata",
51 | "formdata": []
52 | },
53 | "description": "OAuth1.0a is a specification that defines a protocol that can be used by one\nservice to access \"protected\" resources (endpoints) on another service. A\nmajor part of OAuth1.0 is HTTP Request Signing. This endpoint allows you to \ncheck whether the request calculation works properly in the client. \n\nThe endpoint supports the HTTP ``Authorization`` header. In case the signature\nverification fails, the endpoint provides the four debug values,\n\n* ``base_uri``\n* ``normalized_param_string``\n* ``base_string``\n* ``signing_key``\n\nFor more details about these parameters, check the [OAuth1.0a Specification](http://oauth.net/core/1.0a/)\n\nIn order to use this endpoint, you can set the following values:\n\n> Consumer Key: ``RKCGzna7bv9YD57c``\n>\n> Consumer Secret: ``D+EdQ-gs$-%@2Nu7``\n\nIf you are using Postman, also check the \"Add params to header\" and \n\"Auto add parameters\" boxes."
54 | },
55 | "response": []
56 | }
57 | ]
58 | }
59 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**!
2 | * @license http://www.apache.org/licenses/LICENSE-2.0
3 | *
4 | * Copyright 2015 Postdot Technologies Pvt. Ltd.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
13 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and limitations under the License.
15 | */
16 | /**
17 | * @fileOverview This is the entry point to PostmanCollection modules. The structure of the module is defined here.
18 | */
19 | module.exports = require('./lib/index');
20 |
21 |
--------------------------------------------------------------------------------
/lib/collection/certificate-list.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | PropertyList = require('./property-list').PropertyList,
3 | Url = require('./url').Url,
4 | Certificate = require('./certificate').Certificate,
5 |
6 | CertificateList;
7 |
8 | _.inherit((
9 |
10 | /**
11 | * @constructor
12 | * @extends {PropertyList}
13 | *
14 | * @param {Object} parent -
15 | * @param {Array} list - The list of certificate representations
16 | *
17 | * @example
Create a new CertificateList
18 | * var CertificateList = require('postman-collection').CertificateList,
19 | * certificateList = new CertificateList({}, [
20 | * {
21 | * name: 'my certificate for example.com',
22 | * matches: ['https://example.com/*'],
23 | * key: { src: '/path/to/key/file' },
24 | * cert: { src: '/path/to/certificate/file' }
25 | * },
26 | * {
27 | * name: 'my certificate for example2.com',
28 | * matches: ['https://example2.com/*'],
29 | * key: { src: '/path/to/key/file' },
30 | * cert: { src: '/path/to/key/file' }
31 | * }
32 | * ]);
33 | */
34 | CertificateList = function (parent, list) {
35 | // this constructor is intended to inherit and as such the super constructor is required to be executed
36 | CertificateList.super_.call(this, Certificate, parent, list);
37 | }), PropertyList);
38 |
39 | _.assign(CertificateList.prototype, /** @lends CertificateList.prototype */ {
40 | /**
41 | * Matches the given url against the member certificates' allowed matches
42 | * and returns the certificate that can be used for the url.
43 | *
44 | * @param {String} url The url to find the certificate for
45 | * @returns {Certificate.definition=} The matched certificate
46 | */
47 | resolveOne (url) {
48 | // url must be either string or an instance of url.
49 | if (!_.isString(url) && !Url.isUrl(url)) {
50 | return;
51 | }
52 |
53 | // find a certificate that can be applied to the url
54 | return this.find(function (certificate) {
55 | return certificate.canApplyTo(url);
56 | });
57 | }
58 | });
59 |
60 | _.assign(CertificateList, /** @lends CertificateList */ {
61 | /**
62 | * Defines the name of this property for internal use.
63 | *
64 | * @private
65 | * @readOnly
66 | * @type {String}
67 | */
68 | _postman_propertyName: 'CertificateList',
69 |
70 | /**
71 | * Checks if the given object is a CertificateList
72 | *
73 | * @param {*} obj -
74 | * @returns {Boolean}
75 | */
76 | isCertificateList: function (obj) {
77 | return Boolean(obj) && ((obj instanceof CertificateList) ||
78 | _.inSuperChain(obj.constructor, '_postman_propertyName', CertificateList._postman_propertyName));
79 | }
80 | });
81 |
82 | module.exports = {
83 | CertificateList
84 | };
85 |
--------------------------------------------------------------------------------
/lib/collection/certificate.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | Property = require('./property').Property,
3 | PropertyBase = require('./property-base').PropertyBase,
4 | Url = require('./url').Url,
5 | UrlMatchPatternList = require('../url-pattern/url-match-pattern-list').UrlMatchPatternList,
6 |
7 | STRING = 'string',
8 | HTTPS = 'https',
9 |
10 | Certificate;
11 |
12 | /**
13 | * The following is the object representation accepted as param for the Certificate constructor.
14 | * Also the type of the object returned when {@link Property#toJSON} or {@link Property#toObjectResolved} is called on a
15 | * Certificate instance.
16 | *
17 | * @typedef Certificate.definition
18 | * @property {String} [name] A name for the certificate
19 | * @property {Array} [matches] A list of match patterns
20 | * @property {{ src: (String) }} [key] Object with path on the file system for private key file, as src
21 | * @property {{ src: (String) }} [cert] Object with path on the file system for certificate file, as src
22 | * @property {String} [passphrase] The passphrase for the certificate key
23 | *
24 | * @example JSON definition of an example certificate object
25 | * {
26 | * "name": "My certificate for example.com",
27 | * "matches": ["https://example.com/*"],
28 | * "key": { "src": "/path/to/key" },
29 | * "cert": { "src": "/User/path/to/certificate" },
30 | * "passphrase": "iampassphrase"
31 | * }
32 | */
33 | _.inherit((
34 |
35 | /**
36 | * A Certificate definition that represents the ssl certificate
37 | * to be used for an url.
38 | * Properties can then use the `.toObjectResolved` function to procure an object representation of the property with
39 | * all the variable references replaced by corresponding values.
40 | *
41 | * @constructor
42 | * @extends {Property}
43 | *
44 | * @param {Certificate.definition=} [options] Object with matches, key, cert and passphrase
45 | *
46 | * @example Create a new Certificate
47 | *
48 | * var Certificate = require('postman-collection').Certificate,
49 | * certificate = new Certificate({
50 | * name: 'Certificate for example.com',
51 | * matches: ['example.com'],
52 | * key: { src: '/User/path/to/certificate/key' },
53 | * cert: { src: '/User/path/to/certificate' },
54 | * passphrase: 'iampassphrase'
55 | * });
56 | */
57 | Certificate = function Certificate (options) {
58 | // this constructor is intended to inherit and as such the super constructor is required to be executed
59 | Certificate.super_.apply(this, arguments);
60 |
61 | this.update(options);
62 | }), Property);
63 |
64 | _.assign(Certificate.prototype, /** @lends Certificate.prototype */ {
65 | /**
66 | * Ensure all object have id
67 | *
68 | * @private
69 | */
70 | _postman_propertyRequiresId: true,
71 |
72 | /**
73 | * Updates the certificate with the given properties.
74 | *
75 | * @param {Certificate.definition=} [options] Object with matches, key, cert and passphrase
76 | */
77 | update: function (options) {
78 | // return early if options is empty or invalid
79 | if (!_.isObject(options)) {
80 | return;
81 | }
82 |
83 | _.mergeDefined(this, /** @lends Certificate.prototype */ {
84 | /**
85 | * Unique identifier
86 | *
87 | * @type {String}
88 | */
89 | id: options.id,
90 |
91 | /**
92 | * Name for user reference
93 | *
94 | * @type {String}
95 | */
96 | name: options.name,
97 |
98 | /**
99 | * List of match pattern
100 | *
101 | * @type {UrlMatchPatternList}
102 | */
103 | matches: options.matches && new UrlMatchPatternList({}, options.matches),
104 |
105 | /**
106 | * Private Key
107 | *
108 | * @type {{ src: (string) }}
109 | */
110 | key: _.isObject(options.key) ? options.key : { src: options.key },
111 |
112 | /**
113 | * Certificate
114 | *
115 | * @type {{ src: (string) }}
116 | */
117 | cert: _.isObject(options.cert) ? options.cert : { src: options.cert },
118 |
119 | /**
120 | * PFX or PKCS12 Certificate
121 | *
122 | * @type {{ src: (string) }}
123 | */
124 | pfx: _.isObject(options.pfx) ? options.pfx : { src: options.pfx },
125 |
126 | /**
127 | * passphrase
128 | *
129 | * @type {Object}
130 | */
131 | passphrase: options.passphrase
132 | });
133 | },
134 |
135 | /**
136 | * Checks if the certificate can be applied to a given url
137 | *
138 | * @param {String|Url} url The url string for which the certificate is checked for match.
139 | */
140 | canApplyTo: function (url) {
141 | if (_.isEmpty(url)) {
142 | return false;
143 | }
144 |
145 | // convert url strings to Url
146 | (typeof url === STRING) && (url = new Url(url));
147 |
148 | // this ensures we don't proceed any further for any protocol
149 | // that is not https
150 | if (url.protocol !== HTTPS) {
151 | return false;
152 | }
153 |
154 | // test the input url against allowed matches
155 | return this.matches.test(url);
156 | },
157 |
158 | /**
159 | * Allows the serialization of a {@link Certificate}
160 | *
161 | * This is overridden, in order to ensure that certificate contents are not accidentally serialized,
162 | * which can be a security risk.
163 | */
164 | toJSON: function () {
165 | var obj = PropertyBase.toJSON(this);
166 |
167 | _.unset(obj, 'key.value');
168 | _.unset(obj, 'cert.value');
169 | _.unset(obj, 'pfx.value');
170 |
171 | return obj;
172 | }
173 | });
174 |
175 | _.assign(Certificate, /** @lends Certificate */ {
176 | /**
177 | * Defines the name of this property for internal use
178 | *
179 | * @private
180 | * @readOnly
181 | * @type {String}
182 | */
183 | _postman_propertyName: 'Certificate',
184 |
185 | /**
186 | * Specify the key to be used while indexing this object
187 | *
188 | * @private
189 | * @readOnly
190 | * @type {String}
191 | */
192 | _postman_propertyIndexKey: 'id',
193 |
194 | /**
195 | * Checks if the given object is a Certificate
196 | *
197 | * @param {*} obj -
198 | * @returns {Boolean}
199 | */
200 | isCertificate: function (obj) {
201 | return Boolean(obj) && ((obj instanceof Certificate) ||
202 | _.inSuperChain(obj.constructor, '_postman_propertyName', Certificate._postman_propertyName));
203 | }
204 | });
205 |
206 | module.exports = {
207 | Certificate
208 | };
209 |
--------------------------------------------------------------------------------
/lib/collection/cookie-list.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | PropertyList = require('./property-list').PropertyList,
3 | Cookie = require('./cookie').Cookie,
4 |
5 | CookieList;
6 |
7 | _.inherit((
8 |
9 | /**
10 | * Contains a list of header elements
11 | *
12 | * @constructor
13 | * @param {Object} parent -
14 | * @param {Object[]} cookies -
15 | * @extends {PropertyList}
16 | */
17 | CookieList = function (parent, cookies) {
18 | // this constructor is intended to inherit and as such the super constructor is required to be executed
19 | CookieList.super_.call(this, Cookie, parent, cookies);
20 | }), PropertyList);
21 |
22 | // _.assign(CookieList.prototype, /** @lends CookieList.prototype */ {
23 | // });
24 |
25 | _.assign(CookieList, /** @lends CookieList */ {
26 | /**
27 | * Defines the name of this property for internal use.
28 | *
29 | * @private
30 | * @readOnly
31 | * @type {String}
32 | */
33 | _postman_propertyName: 'CookieList',
34 |
35 | /**
36 | * Checks if the given object is a CookieList
37 | *
38 | * @param {*} obj -
39 | * @returns {Boolean}
40 | */
41 | isCookieList: function (obj) {
42 | return Boolean(obj) && ((obj instanceof CookieList) ||
43 | _.inSuperChain(obj.constructor, '_postman_propertyName', CookieList._postman_propertyName));
44 | }
45 | });
46 |
47 | module.exports = {
48 | CookieList
49 | };
50 |
--------------------------------------------------------------------------------
/lib/collection/description.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 |
3 | E = '',
4 | DEFAULT_MIMETYPE = 'text/plain',
5 |
6 | Description;
7 |
8 | /**
9 | * @typedef Description.definition
10 | * @property {String} content
11 | * @property {String} type
12 | */
13 | /**
14 | * This is one of the properties that are (if provided) processed by all other properties. Any property can have an
15 | * instance of `Description` property assigned to it with the key name `description` and it should be treated as
16 | * something that "describes" the property within which it belongs. Usually this property is used to generate
17 | * documentation and other contextual information for a property in a Collection.
18 | *
19 | * @constructor
20 | *
21 | * @param {Description.definition|String} [definition] The content of the description can be passed as a string when it
22 | * is in `text/plain` format or otherwise be sent as part of an object adhering to the {@link Description.definition}
23 | * structure having `content` and `type`.
24 | *
25 | * @example Add a description to an instance of Collection
26 | * var SDK = require('postman-collection'),
27 | * Collection = SDK.Collection,
28 | * Description = SDK.Description,
29 | * mycollection;
30 | *
31 | * // create a blank collection
32 | * myCollection = new Collection();
33 | * myCollection.description = new Description({
34 | * content: '<h1>Hello World</h1><p>I am a Collection</p>',
35 | * type: 'text/html'
36 | * });
37 | *
38 | * // alternatively, you could also use the `.describe` method of any property to set or update the description of the
39 | * // property.
40 | * myCollection.describe('Hey! This is a cool collection.');
41 | */
42 | Description = function PostmanPropertyDescription (definition) {
43 | // if the definition is a string, it implies that this is a get of URL
44 | _.isString(definition) && (definition = {
45 | content: definition,
46 | type: DEFAULT_MIMETYPE
47 | });
48 |
49 | // populate the description
50 | definition && this.update(definition);
51 | };
52 |
53 | _.assign(Description.prototype, /** @lends Description.prototype */ {
54 | /**
55 | * Updates the content of this description property.
56 | *
57 | * @param {String|Description.definition} content -
58 | * @param {String=} [type] -
59 | * @todo parse version of description
60 | */
61 | update (content, type) {
62 | _.isObject(content) && ((type = content.type), (content = content.content));
63 | _.assign(this, /** @lends Description.prototype */ {
64 | /**
65 | * The raw content of the description
66 | *
67 | * @type {String}
68 | */
69 | content: content,
70 |
71 | /**
72 | * The mime-type of the description.
73 | *
74 | * @type {String}
75 | */
76 | type: type || DEFAULT_MIMETYPE
77 | });
78 | },
79 |
80 | /**
81 | * Returns stringified Description.
82 | *
83 | * @returns {String}
84 | */
85 | toString () {
86 | return this.content || E;
87 | },
88 |
89 | /**
90 | * Creates a JSON representation of the Description (as a plain Javascript object).
91 | *
92 | * @returns {{content: *, type: *, version: (String|*)}}
93 | */
94 | toJSON () {
95 | return {
96 | content: this.content,
97 | type: this.type
98 | };
99 | }
100 | });
101 |
102 | _.assign(Description, /** @lends Description */ {
103 | /**
104 | * Defines the name of this property for internal use.
105 | *
106 | * @private
107 | * @readOnly
108 | * @type {String}
109 | */
110 | _postman_propertyName: 'Description',
111 |
112 | /**
113 | * Checks whether a property is an instance of Description object.
114 | *
115 | * @param {*} obj -
116 | * @returns {Boolean}
117 | */
118 | isDescription: function (obj) {
119 | return Boolean(obj) && ((obj instanceof Description) ||
120 | _.inSuperChain(obj.constructor, '_postman_propertyName', Description._postman_propertyName));
121 | }
122 | });
123 |
124 | module.exports = {
125 | Description
126 | };
127 |
--------------------------------------------------------------------------------
/lib/collection/event-list.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | PropertyList = require('./property-list').PropertyList,
3 | Event = require('./event').Event,
4 |
5 | EventList;
6 |
7 | _.inherit((
8 |
9 | /**
10 | * A type of {@link PropertyList}, EventList handles resolving events from parents. If an {@link ItemGroup} contains
11 | * a set of events, each {@link Item} in that group will inherit those events from its parent, and so on.
12 | *
13 | * @constructor
14 | * @param {Object} parent -
15 | * @param {Object[]} populate -
16 | * @extends {PropertyList}
17 | *
18 | * This is useful when we need to have a common test across all requests.
19 | */
20 | EventList = function PostmanEventList (parent, populate) {
21 | // this constructor is intended to inherit and as such the super constructor is required to be executed
22 | EventList.super_.call(this, Event, parent, populate);
23 | }), PropertyList);
24 |
25 | _.assign(EventList.prototype, /** @lends EventList.prototype */ {
26 | /**
27 | * Returns an array of listeners filtered by the listener name
28 | *
29 | * @note
30 | * If one needs to access disabled events, use {@link PropertyList#all} or
31 | * any other similar {@link PropertyList} method.
32 | *
33 | * @param {String} name -
34 | * @returns {Array}
35 | */
36 | listeners (name) {
37 | var all;
38 |
39 | // we first procure all matching events from this list
40 | all = this.listenersOwn(name);
41 |
42 | this.eachParent(function (parent) {
43 | var parentEvents;
44 |
45 | // we check that the parent is not immediate mother. then we check whether the non immediate mother has a
46 | // valid `events` store and only if this store has events with specified listener, we push them to the
47 | // array we are compiling for return
48 | (parent !== this.__parent) && EventList.isEventList(parent.events) &&
49 | (parentEvents = parent.events.listenersOwn(name)) && parentEvents.length &&
50 | all.unshift.apply(all, parentEvents); // eslint-disable-line prefer-spread
51 | }, this);
52 |
53 | return all;
54 | },
55 |
56 | /**
57 | * Returns all events with specific listeners only within this list. Refer to {@link EventList#listeners} for
58 | * procuring all inherited events
59 | *
60 | * @param {string} name -
61 | * @returns {Array}
62 | */
63 | listenersOwn (name) {
64 | return this.filter(function (event) {
65 | return (!event.disabled && event.listen === name);
66 | });
67 | }
68 | });
69 |
70 | _.assign(EventList, /** @lends EventList */ {
71 | /**
72 | * Defines the name of this property for internal use.
73 | *
74 | * @private
75 | * @readOnly
76 | * @type {String}
77 | */
78 | _postman_propertyName: 'EventList',
79 |
80 | /**
81 | * Checks if the given object is an EventList.
82 | *
83 | * @param {*} obj -
84 | * @returns {Boolean}
85 | */
86 | isEventList: function (obj) {
87 | return Boolean(obj) && ((obj instanceof EventList) ||
88 | _.inSuperChain(obj.constructor, '_postman_propertyName', EventList._postman_propertyName));
89 | }
90 | });
91 |
92 | module.exports = {
93 | EventList
94 | };
95 |
--------------------------------------------------------------------------------
/lib/collection/event.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | Property = require('./property').Property,
3 | Script = require('./script').Script,
4 |
5 | Event;
6 |
7 | /**
8 | * @typedef Event.definition
9 | * @property {String} listen The event-name that this script will be called for. Usually either "test" or "prerequest"
10 | * @property {Script|String} script A {@link Script} instance that will be executed on this event. In case of a
11 | * string, a new {@link Script} is created.
12 | * @example Constructing an event
13 | * var Event = require('postman-collection').Event,
14 | * rawEvent = {
15 | * listen: 'test',
16 | * script: 'tests["response code is 401"] = responseCode.code === 401'
17 | * },
18 | * myEvent;
19 | * myEvent = new Event(rawEvent);
20 | */
21 | _.inherit((
22 |
23 | /**
24 | * A Postman event definition that refers to an event to be listened to and a script reference or definition to be
25 | * executed.
26 | *
27 | * @constructor
28 | * @extends {Property}
29 | *
30 | * @param {Event.definition} definition Pass the initial definition of the event as the options parameter.
31 | */
32 | Event = function PostmanEvent (definition) {
33 | // this constructor is intended to inherit and as such the super constructor is required to be executed
34 | Event.super_.call(this, definition);
35 | // set initial values of this event
36 | definition && this.update(definition);
37 | }), Property);
38 |
39 | _.assign(Event.prototype, /** @lends Event.prototype */ {
40 | /**
41 | * Update an event.
42 | *
43 | * @param {Event.definition} definition -
44 | */
45 | update (definition) {
46 | if (!definition) {
47 | return;
48 | }
49 |
50 | var result,
51 | script = definition.script;
52 |
53 | if (Script.isScript(script)) {
54 | result = script;
55 | }
56 | else if (_.isArray(script) || _.isString(script)) {
57 | result = new Script({ exec: script });
58 | }
59 | else if (_.isObject(script)) {
60 | result = new Script(script);
61 | }
62 |
63 | _.mergeDefined(this, /** @lends Event.prototype */ {
64 | /**
65 | * Name of the event that this instance is intended to listen to.
66 | *
67 | * @type {String}
68 | */
69 | listen: _.isString(definition.listen) ? definition.listen : undefined,
70 |
71 | /**
72 | * The script that is to be executed when this event is triggered.
73 | *
74 | * @type {Script}
75 | */
76 | script: result
77 | });
78 | }
79 | });
80 |
81 | _.assign(Event, /** @lends Event */ {
82 |
83 | /**
84 | * Defines the name of this property for internal use.
85 | *
86 | * @private
87 | * @readOnly
88 | * @type {String}
89 | */
90 | _postman_propertyName: 'Event',
91 |
92 | /**
93 | * Check whether an object is an instance of {@link Event}.
94 | *
95 | * @param {*} obj -
96 | * @returns {Boolean}
97 | */
98 | isEvent: function isPostmanEvent (obj) {
99 | return Boolean(obj) && ((obj instanceof Event) ||
100 | _.inSuperChain(obj.constructor, '_postman_propertyName', Event._postman_propertyName));
101 | }
102 | });
103 |
104 | module.exports = {
105 | Event
106 | };
107 |
--------------------------------------------------------------------------------
/lib/collection/form-param.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | Property = require('./property').Property,
3 | PropertyBase = require('./property-base').PropertyBase,
4 |
5 | FormParam;
6 |
7 | /**
8 | * @typedef FormParam.definition
9 | * @property {String} key The name ("key") of the form data parameter.
10 | * @property {String} value The value of the parameter.
11 | */
12 | _.inherit((
13 |
14 | /**
15 | * Represents a Form Data parameter, which can exist in request body.
16 | *
17 | * @constructor
18 | * @param {FormParam.definition} options Pass the initial definition of the form data parameter.
19 | */
20 | FormParam = function PostmanFormParam (options = {}) {
21 | FormParam.super_.apply(this, arguments);
22 |
23 | this.key = options.key || '';
24 | this.value = options.value || '';
25 | this.type = options.type;
26 | this.src = options.src;
27 | this.contentType = options.contentType;
28 | this.fileName = options.fileName;
29 | }), Property);
30 |
31 | _.assign(FormParam.prototype, /** @lends FormParam.prototype */ {
32 | /**
33 | * Converts the FormParameter to a single param string.
34 | *
35 | * @returns {String}
36 | */
37 | toString () {
38 | return this.key + '=' + this.value;
39 | },
40 |
41 | /**
42 | * Returns the value of the form parameter (if any).
43 | *
44 | * @returns {*|String}
45 | */
46 | valueOf () {
47 | return this.value; // can be multiple types, so just return whatever we have instead of being too clever
48 | },
49 |
50 | /**
51 | * Convert the form-param to JSON compatible plain object.
52 | *
53 | * @returns {Object}
54 | */
55 | toJSON () {
56 | var obj = PropertyBase.toJSON(this);
57 |
58 | // remove value from file param if it's empty or non-string (can be non-serializable ReadStream)
59 | if (obj.type === 'file' && (typeof obj.value !== 'string' || !obj.value)) {
60 | _.unset(obj, 'value');
61 | }
62 |
63 | return obj;
64 | }
65 | });
66 |
67 | _.assign(FormParam, /** @lends FormParam */ {
68 |
69 | /**
70 | * Defines the name of this property for internal use.
71 | *
72 | * @private
73 | * @readOnly
74 | * @type {String}
75 | */
76 | _postman_propertyName: 'FormParam',
77 |
78 | /**
79 | * Declare the list index key, so that property lists of form parameters work correctly
80 | *
81 | * @type {String}
82 | */
83 | _postman_propertyIndexKey: 'key',
84 |
85 | /**
86 | * Form params can have multiple values, so set this to true.
87 | *
88 | * @type {Boolean}
89 | */
90 | _postman_propertyAllowsMultipleValues: true,
91 |
92 | /**
93 | * Parse a form data string into an array of objects, where each object contains a key and a value.
94 | *
95 | * @todo implement this, not implemented yet.
96 | * @param formdata {String}
97 | * @returns {Array}
98 | */
99 | parse: _.noop
100 | });
101 |
102 | module.exports = {
103 | FormParam
104 | };
105 |
--------------------------------------------------------------------------------
/lib/collection/header-list.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | PropertyList = require('./property-list').PropertyList,
3 | Header = require('./header').Header,
4 |
5 | PROP_NAME = '_postman_propertyName',
6 |
7 | HeaderList;
8 |
9 | _.inherit((
10 |
11 | /**
12 | * Contains a list of header elements
13 | *
14 | * @constructor
15 | * @param {Object} parent -
16 | * @param {Header[]} headers -
17 | * @extends {PropertyList}
18 | */
19 | HeaderList = function (parent, headers) {
20 | // this constructor is intended to inherit and as such the super constructor is required to be executed
21 | HeaderList.super_.call(this, Header, parent, headers);
22 | }), PropertyList);
23 |
24 | _.assign(HeaderList.prototype, /** @lends HeaderList.prototype */ {
25 | /**
26 | * Gets size of a list of headers excluding standard header prefix.
27 | *
28 | * @returns {Number}
29 | */
30 | contentSize () {
31 | if (!this.count()) { return 0; }
32 |
33 | return Header.unparse(this).length;
34 | }
35 | });
36 |
37 | _.assign(HeaderList, /** @lends HeaderList */ {
38 | /**
39 | * Defines the name of this property for internal use.
40 | *
41 | * @private
42 | * @readOnly
43 | * @type {String}
44 | */
45 | _postman_propertyName: 'HeaderList',
46 |
47 | /**
48 | * Checks if the given object is a HeaderList
49 | *
50 | * @param {*} obj -
51 | * @returns {Boolean}
52 | */
53 | isHeaderList: function (obj) {
54 | return Boolean(obj) && ((obj instanceof HeaderList) ||
55 | _.inSuperChain(obj.constructor, PROP_NAME, HeaderList._postman_propertyName));
56 | }
57 | });
58 |
59 | module.exports = {
60 | HeaderList
61 | };
62 |
--------------------------------------------------------------------------------
/lib/collection/property-base.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 |
3 | __PARENT = '__parent',
4 |
5 | PropertyBase; // constructor
6 |
7 | /**
8 | * @typedef PropertyBase.definition
9 | * @property {String|Description} [description]
10 | */
11 | /**
12 | * Base of all properties in Postman Collection. It defines the root for all standalone properties for postman
13 | * collection.
14 | *
15 | * @constructor
16 | * @param {PropertyBase.definition} definition -
17 | */
18 | PropertyBase = function PropertyBase (definition) {
19 | // In case definition object is missing, there is no point moving forward. Also if the definition is basic string
20 | // we do not need to do anything with it.
21 | if (!definition || typeof definition === 'string') { return; }
22 |
23 | // call the meta extraction functions to create the object where all keys that are prefixed with underscore can be
24 | // stored. more details on that can be retrieved from the propertyExtractMeta function itself.
25 | // @todo: make this a closed function to do getter and setter which is non enumerable
26 | var src = definition && definition.info || definition,
27 | meta = _(src).pickBy(PropertyBase.propertyIsMeta).mapKeys(PropertyBase.propertyUnprefixMeta).value();
28 |
29 | if (_.keys(meta).length) {
30 | this._ = _.isObject(this._) ?
31 | /* istanbul ignore next */
32 | _.mergeDefined(this._, meta) :
33 | meta;
34 | }
35 | };
36 |
37 | _.assign(PropertyBase.prototype, /** @lends PropertyBase.prototype */ {
38 |
39 | /**
40 | * Invokes the given iterator for every parent in the parent chain of the given element.
41 | *
42 | * @param {Object} options - A set of options for the parent chain traversal.
43 | * @param {?Boolean} [options.withRoot=false] - Set to true to include the collection object as well.
44 | * @param {Function} iterator - The function to call for every parent in the ancestry chain.
45 | * @todo Cache the results
46 | */
47 | forEachParent (options, iterator) {
48 | _.isFunction(options) && (iterator = options, options = {});
49 | if (!_.isFunction(iterator) || !_.isObject(options)) { return; }
50 |
51 | var parent = this.parent(),
52 | grandparent = parent && _.isFunction(parent.parent) && parent.parent();
53 |
54 | while (parent && (grandparent || options.withRoot)) {
55 | iterator(parent);
56 | parent = grandparent;
57 | grandparent = grandparent && _.isFunction(grandparent.parent) && grandparent.parent();
58 | }
59 | },
60 |
61 | /**
62 | * Tries to find the given property locally, and then proceeds to lookup in each parent,
63 | * going up the chain as necessary. Lookup will continue until `customizer` returns a truthy value. If used
64 | * without a customizer, the lookup will stop at the first parent that contains the property.
65 | *
66 | * @param {String} property -
67 | * @param {Function} [customizer] -
68 | * @returns {*|undefined}
69 | */
70 | findInParents (property, customizer) {
71 | var owner = this.findParentContaining(property, customizer);
72 |
73 | return owner ? owner[property] : undefined;
74 | },
75 |
76 | /**
77 | * Looks up the closest parent which has a truthy value for the given property. Lookup will continue
78 | * until `customizer` returns a truthy value. If used without a customizer,
79 | * the lookup will stop at the first parent that contains the property.
80 | *
81 | * @private
82 | * @param {String} property -
83 | * @param {Function} [customizer] -
84 | * @returns {PropertyBase|undefined}
85 | */
86 | findParentContaining (property, customizer) {
87 | var parent = this;
88 |
89 | // if customizer is present test with it
90 | if (customizer) {
91 | customizer = customizer.bind(this);
92 |
93 | do {
94 | // else check for existence
95 | if (customizer(parent)) {
96 | return parent;
97 | }
98 |
99 | parent = parent.__parent;
100 | } while (parent);
101 | }
102 |
103 | // else check for existence
104 | else {
105 | do {
106 | if (parent[property]) {
107 | return parent;
108 | }
109 |
110 | parent = parent.__parent;
111 | } while (parent);
112 | }
113 | },
114 |
115 | /**
116 | * Returns the JSON representation of a property, which conforms to the way it is defined in a collection.
117 | * You can use this method to get the instantaneous representation of any property, including a {@link Collection}.
118 | */
119 | toJSON () {
120 | return _.reduce(this, function (accumulator, value, key) {
121 | if (value === undefined) { // true/false/null need to be preserved.
122 | return accumulator;
123 | }
124 |
125 | // Handle plurality of PropertyLists in the SDK vs the exported JSON.
126 | // Basically, removes the trailing "s" from key if the value is a property list.
127 | // eslint-disable-next-line @stylistic/js/max-len
128 | if (value && value._postman_propertyIsList && !value._postman_proprtyIsSerialisedAsPlural && _.endsWith(key, 's')) {
129 | key = key.slice(0, -1);
130 | }
131 |
132 | // Handle 'PropertyBase's
133 | if (value && _.isFunction(value.toJSON)) {
134 | accumulator[key] = value.toJSON();
135 |
136 | return accumulator;
137 | }
138 |
139 | // Handle Strings
140 | if (_.isString(value)) {
141 | accumulator[key] = value;
142 |
143 | return accumulator;
144 | }
145 |
146 | // Everything else
147 | accumulator[key] = _.cloneElement(value);
148 |
149 | return accumulator;
150 | }, {});
151 | },
152 |
153 | /**
154 | * Returns the meta keys associated with the property
155 | *
156 | * @returns {*}
157 | */
158 | meta () {
159 | return arguments.length ? _.pick(this._, Array.prototype.slice.apply(arguments)) : _.cloneDeep(this._);
160 | },
161 |
162 | /**
163 | * Returns the parent of item
164 | *
165 | * @returns {*|undefined}
166 | */
167 | parent () {
168 | let parent = this.__parent;
169 |
170 | // if the parent is a list, return the grandparent
171 | if (parent && parent._postman_propertyIsList) {
172 | parent = parent.__parent || parent;
173 | }
174 |
175 | return parent || undefined;
176 | },
177 |
178 | /**
179 | * Accepts an object and sets it as the parent of the current property.
180 | *
181 | * @param {Object} parent The object to set as parent.
182 | * @private
183 | */
184 | setParent (parent) {
185 | _.assignHidden(this, __PARENT, parent);
186 | }
187 | });
188 |
189 | _.assign(PropertyBase, /** @lends PropertyBase */ {
190 |
191 | /**
192 | * Defines the name of this property for internal use.
193 | *
194 | * @private
195 | * @readOnly
196 | * @type {String}
197 | */
198 | _postman_propertyName: 'PropertyBase',
199 |
200 | /**
201 | * Filter function to check whether a key starts with underscore or not. These usually are the meta properties. It
202 | * returns `true` if the criteria is matched.
203 | *
204 | * @param {*} value -
205 | * @param {String} key -
206 | *
207 | * @returns {boolean}
208 | */
209 | propertyIsMeta: function (value, key) {
210 | return _.startsWith(key, '_') && (key !== '_');
211 | },
212 |
213 | /**
214 | * Map function that removes the underscore prefix from an object key.
215 | *
216 | * @param {*} value -
217 | * @param {String} key -
218 | * @returns {String}
219 | */
220 | propertyUnprefixMeta: function (value, key) {
221 | return _.trimStart(key, '_');
222 | },
223 |
224 | /**
225 | * Static function which allows calling toJSON() on any object.
226 | *
227 | * @param {Object} obj -
228 | * @returns {*}
229 | */
230 | toJSON: function (obj) {
231 | return PropertyBase.prototype.toJSON.call(obj);
232 | }
233 | });
234 |
235 | module.exports = {
236 | PropertyBase
237 | };
238 |
--------------------------------------------------------------------------------
/lib/collection/proxy-config-list.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | PropertyList = require('./property-list').PropertyList,
3 | ProxyConfig = require('./proxy-config').ProxyConfig,
4 | Url = require('./url').Url,
5 |
6 | ProxyConfigList;
7 |
8 | _.inherit((
9 |
10 | /**
11 | * @constructor
12 | * @extends {PropertyList}
13 | *
14 | * @param {Object} parent -
15 | * @param {Array} populate The list of proxy objects
16 | *
17 | * @example Create a new ProxyConfigList
18 | * var ProxyConfigList = require('postman-collection').ProxyConfigList,
19 | * myProxyConfig = new ProxyConfigList({}, [
20 | * {match: 'https://example.com/*', host: 'proxy.com', port: 8080, tunnel: true},
21 | * {match: 'http+https://example2.com/*', host: 'proxy2.com'},
22 | * ]);
23 | */
24 | ProxyConfigList = function PostmanProxyConfigList (parent, populate) {
25 | // this constructor is intended to inherit and as such the super constructor is required to be executed
26 | ProxyConfigList.super_.call(this, ProxyConfig, parent, populate);
27 | }), PropertyList);
28 |
29 | _.assign(ProxyConfigList.prototype, /** @lends ProxyConfigList.prototype */ {
30 | /**
31 | * Matches and gets the proxy config for the particular url.
32 | *
33 | * @returns {ProxyConfig.definition} The matched proxyConfig object
34 | * @param {URL=} [url] The url for which the proxy config needs to be fetched
35 | */
36 | resolve (url) {
37 | // url must be either string or an instance of url.
38 | if (!_.isString(url) && !Url.isUrl(url)) {
39 | return;
40 | }
41 |
42 | // @todo - use a fixed-length cacheing of regexes in future
43 | return this.find(function (proxyConfig) {
44 | return !proxyConfig.disabled && proxyConfig.test(url);
45 | });
46 | }
47 | });
48 |
49 | _.assign(ProxyConfigList, /** @lends ProxyConfigList */ {
50 | /**
51 | * Defines the name of this property for internal use.
52 | *
53 | * @private
54 | * @readOnly
55 | * @type {String}
56 | *
57 | * @note that this is directly accessed only in case of ProxyConfigList from _.findValue lodash util mixin
58 | */
59 | _postman_propertyName: 'ProxyConfigList',
60 |
61 | /**
62 | * Checks whether an object is a ProxyConfigList
63 | *
64 | * @param {*} obj -
65 | * @returns {Boolean}
66 | */
67 | isProxyConfigList: function (obj) {
68 | return Boolean(obj) && ((obj instanceof ProxyConfigList) ||
69 | _.inSuperChain(obj.constructor, '_postman_propertyName', ProxyConfigList._postman_propertyName));
70 | }
71 | });
72 |
73 | module.exports = {
74 | ProxyConfigList
75 | };
76 |
--------------------------------------------------------------------------------
/lib/collection/request-auth.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | Property = require('./property').Property,
3 | VariableList = require('./variable-list').VariableList,
4 |
5 | RequestAuth;
6 |
7 | /**
8 | * This defines the definition of the authentication method to be used.
9 | *
10 | * @typedef RequestAuth.definition
11 | * @property {String=} type The Auth type to use. Check the names in {@link AuthTypes}
12 | *
13 | * @example Sample auth definition for Basic Auth
14 | * {
15 | * "type": "basic",
16 | * "basic": [
17 | * { "key": "username", "value": "postman" },
18 | * { "key": "password", "value": "secrets" }
19 | * ]
20 | * }
21 | */
22 | _.inherit((
23 |
24 | /**
25 | * A Postman Auth definition that comprehensively represents different types of auth mechanisms available.
26 | *
27 | * @constructor
28 | * @extends {Property}
29 | *
30 | * @param {RequestAuth.definition} options Pass the initial definition of the Auth.
31 | * @param {Property|PropertyList=} [parent] optionally pass the parent of this auth. aides variable resolution.
32 | *
33 | * @example Creating a request with two auth data and one selected
34 | * var auth = new RequestAuth({
35 | * type: 'digest',
36 | *
37 | * basic: [
38 | * { key: "username", value: "postman" },
39 | * { key: "password", value: "secrets" }
40 | * ],
41 | * digest: [
42 | * { key: "nonce", value: "aef54cde" },
43 | * { key: "realm", value: "items.x" }
44 | * ]
45 | * });
46 | *
47 | * // change the selected auth
48 | * auth.use('basic');
49 | */
50 | RequestAuth = function PostmanRequestAuth (options, parent) {
51 | // this constructor is intended to inherit and as such the super constructor is required to be executed
52 | RequestAuth.super_.call(this, options);
53 |
54 | // set the parent
55 | parent && this.setParent(parent);
56 |
57 | // set the type, if passed via options
58 | if (_.has(options, 'type')) {
59 | this.use(options.type);
60 | }
61 |
62 | // load all possible auth parameters from options
63 | _.forEach(_.omit(options, 'type'), this.update.bind(this));
64 | }), Property);
65 |
66 | _.assign(RequestAuth.prototype, /** @lends RequestAuth.prototype */ {
67 | /**
68 | * Update the parameters of a specific authentication type. If none is provided then it uses the one marked as to be
69 | * used.
70 | *
71 | * @param {VariableList|Array|Object} options -
72 | * @param {String=} [type=this.type] -
73 | */
74 | update (options, type) {
75 | // update must have options
76 | if (!_.isObject(options)) { return; }
77 | // choose default from existing type if not provided
78 | if (!type) { type = this.type; }
79 | // validate type parameter and return in case type is not valid.
80 | if (!RequestAuth.isValidType(type)) { return; }
81 |
82 | var parameters = this[type];
83 |
84 | // in case the type holder is not created, we create one and send the population variables
85 | if (!VariableList.isVariableList(parameters)) {
86 | // @todo optimise the handling of legacy object type auth parameters
87 | parameters = this[type] = new VariableList(this);
88 | parameters._postman_requestAuthType = type;
89 | }
90 |
91 | // we simply assimilate the new options either it is an array or an object
92 | if (_.isArray(options) || VariableList.isVariableList(options)) {
93 | parameters.assimilate(options);
94 | }
95 | else {
96 | parameters.syncFromObject(options, false, false); // params: no need to track and no need to prune
97 | }
98 | },
99 |
100 | /**
101 | * Sets the authentication type to be used by this item.
102 | *
103 | * @param {String} type -
104 | * @param {VariableList|Array|Object} options - note that options set here would replace all existing
105 | * options for the particular auth
106 | */
107 | use (type, options) {
108 | if (!RequestAuth.isValidType(type)) { return; }
109 |
110 | this.type = type; // set the type
111 |
112 | var parameters = this[type];
113 |
114 | if (!VariableList.isVariableList(parameters)) {
115 | parameters = this[type] = new VariableList(this);
116 | }
117 |
118 | // we simply assimilate the new options either it is an array or an object
119 | if (_.isArray(options) || VariableList.isVariableList(options)) {
120 | parameters.assimilate(options);
121 | }
122 | else {
123 | parameters.syncFromObject(options, false, false); // params: no need to track and no need to prune
124 | }
125 | },
126 |
127 | /**
128 | * @private
129 | * @deprecated discontinued in v4.0
130 | */
131 | current () {
132 | throw new Error('`Request#current` has been discontinued, use `Request#parameters` instead.');
133 | },
134 |
135 | /**
136 | * Returns the parameters of the selected auth type
137 | *
138 | * @returns {VariableList}
139 | */
140 | parameters () {
141 | return this[this.type];
142 | },
143 |
144 | /**
145 | * Clears the definition of an auth type.
146 | *
147 | * @param {String} type -
148 | */
149 | clear (type) {
150 | if (!(RequestAuth.isValidType(type) && VariableList.isVariableList(this[type]))) {
151 | return;
152 | }
153 |
154 | // clear the variable list
155 | this[type].clear();
156 |
157 | // if it is not a currently selected auth type, do not delete the variable list, but simply delete it
158 | if (type !== this.type) {
159 | delete this[type];
160 | }
161 | }
162 | });
163 |
164 | _.assign(RequestAuth, /** @lends RequestAuth */ {
165 | /**
166 | * Defines the name of this property for internal use.
167 | *
168 | * @private
169 | * @readOnly
170 | * @type {String}
171 | */
172 | _postman_propertyName: 'RequestAuth',
173 |
174 | /**
175 | * Determines whether an authentication type name is valid or not
176 | *
177 | * @param {String} type -
178 | * @returns {Boolean}
179 | */
180 | isValidType: function (type) {
181 | // no auth name can be "type", else will have namespace collision with type selector
182 | return _.isString(type) && (type !== 'type');
183 | }
184 | });
185 |
186 | module.exports = {
187 | RequestAuth
188 | };
189 |
--------------------------------------------------------------------------------
/lib/collection/script.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | Property = require('./property').Property,
3 | Url = require('./url').Url,
4 |
5 | Script,
6 |
7 | SCRIPT_NEWLINE_PATTERN = /\r?\n/g;
8 |
9 | /**
10 | * A map of package names to the IDs of the packages
11 | *
12 | * @typedef {Object.} Packages
13 | */
14 |
15 | _.inherit((
16 |
17 | /**
18 | * Postman scripts that are executed upon events on a collection / request such as test and pre request.
19 | *
20 | * @constructor
21 | * @extends {Property}
22 | *
23 | * @param {Object} options -
24 | */
25 | Script = function PostmanScript (options) {
26 | // this constructor is intended to inherit and as such the super constructor is required to be executed
27 | Script.super_.apply(this, arguments);
28 |
29 | options && this.update(options);
30 | }), Property);
31 |
32 | _.assign(Script.prototype, /** @lends Script.prototype */ {
33 | /**
34 | * Defines whether this property instances requires an id
35 | *
36 | * @private
37 | * @readOnly
38 | * @type {Boolean}
39 | */
40 | _postman_propertyRequiresId: true,
41 |
42 | /**
43 | * Converts the script lines array to a single source string.
44 | *
45 | * @returns {String}
46 | */
47 | toSource: function () {
48 | return this.exec ? this.exec.join('\n') : undefined;
49 | },
50 |
51 | /**
52 | * Updates the properties of a Script.
53 | *
54 | * @param {Object} [options] -
55 | * @param {String} [options.type] Script type
56 | * @param {String} [options.src] Script source url
57 | * @param {String[]|String} [options.exec] Script to execute
58 | * @param {Packages} [options.packages] Packages required by the script
59 | */
60 | update: function (options) {
61 | // no splitting is being done here, as string scripts are split right before assignment below anyway
62 | (_.isString(options) || _.isArray(options)) && (options = { exec: options });
63 |
64 | if (!options) { return; } // in case definition object is missing, there is no point moving forward
65 |
66 | // create the request property
67 | /**
68 | * @augments {Script.prototype}
69 | * @type {string}
70 | */
71 | this.type = options.type || 'text/javascript';
72 |
73 | /**
74 | * The packages required by the script
75 | *
76 | * @type {Packages}
77 | */
78 | this.packages = options.packages;
79 |
80 | _.has(options, 'src') && (
81 |
82 | /**
83 | * @augments {Script.prototype}
84 | * @type {Url}
85 | */
86 | this.src = new Url(options.src)
87 | );
88 |
89 | if (!this.src && _.has(options, 'exec')) {
90 | /**
91 | * @augments {Script.prototype}
92 | * @type {Array}
93 | */
94 | this.exec = _.isString(options.exec) ? options.exec.split(SCRIPT_NEWLINE_PATTERN) :
95 | _.isArray(options.exec) ? options.exec : undefined;
96 | }
97 | },
98 |
99 | /**
100 | * Checks if the script is empty i.e does not have any code to execute.
101 | *
102 | * @returns {Boolean}
103 | */
104 | isEmpty: function () {
105 | return _.isEmpty(_.trim(this.toSource()));
106 | }
107 | });
108 |
109 | _.assign(Script, /** @lends Script */ {
110 | /**
111 | * Defines the name of this property for internal use.
112 | *
113 | * @private
114 | * @readOnly
115 | * @type {String}
116 | */
117 | _postman_propertyName: 'Script',
118 |
119 | /**
120 | * Check whether an object is an instance of {@link ItemGroup}.
121 | *
122 | * @param {*} obj -
123 | * @returns {Boolean}
124 | */
125 | isScript: function (obj) {
126 | return Boolean(obj) && ((obj instanceof Script) ||
127 | _.inSuperChain(obj.constructor, '_postman_propertyName', Script._postman_propertyName));
128 | }
129 | });
130 |
131 | module.exports = {
132 | Script
133 | };
134 |
--------------------------------------------------------------------------------
/lib/collection/variable-list.js:
--------------------------------------------------------------------------------
1 | var _ = require('../util').lodash,
2 | PropertyList = require('./property-list').PropertyList,
3 | Property = require('./property').Property,
4 | Variable = require('./variable').Variable,
5 |
6 | VariableList;
7 |
8 | _.inherit((
9 |
10 | /**
11 | * @constructor
12 | * @extends {PropertyList}
13 | *
14 | * @param {Property} parent -
15 | * @param {Object|Array} populate -
16 | */
17 | VariableList = function PostmanVariableList (parent, populate) {
18 | // this constructor is intended to inherit and as such the super constructor is required to be executed
19 | VariableList.super_.call(this, Variable, parent, populate);
20 | }), PropertyList);
21 |
22 | _.assign(VariableList.prototype, /** @lends VariableList.prototype */ {
23 | /**
24 | * Replaces the variable tokens inside a string with its actual values.
25 | *
26 | * @param {String} str -
27 | * @param {Object} [overrides] - additional objects to lookup for variable values
28 | * @returns {String}
29 | */
30 | replace (str, overrides) {
31 | return Property.replaceSubstitutions(str, this, overrides);
32 | },
33 |
34 | /**
35 | * Recursively replace strings in an object with instances of variables. Note that it clones the original object. If
36 | * the `mutate` param is set to true, then it replaces the same object instead of creating a new one.
37 | *
38 | * @param {Array|Object} obj -
39 | * @param {?Array