├── .appveyor.yml ├── .bmp.yml ├── .changelog ├── CHANGELOG.tpl#mkd └── config.yml ├── .codacy.yml ├── .codeclimate.yml ├── .codecov.yml ├── .commitlint.config.js ├── .deps-lock ├── .gitattributes ├── package-lock.json └── yarn.lock ├── .ecrc.JS.json ├── .editorconfig ├── .eslintrc.js ├── .gitattributes ├── .github └── workflows │ └── CI.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── .remarkrc.js ├── .rollup.config.types.js ├── .scrutinizer.yml ├── .vscode ├── cspell.dictionaries │ ├── acronyms+names.wordlist.txt │ ├── jargon.wordlist.txt │ ├── people.wordlist.txt │ └── shell.wordlist.txt ├── cspell.json ├── extensions.json └── settings.json ├── .yarn └── releases │ └── yarn-1.22.19.cjs ├── .yarnrc ├── .yarnrc.yml ├── CHANGELOG.mkd ├── LICENSE ├── README.md ├── VERSION ├── cjs └── package.json ├── dist ├── cjs │ ├── esm-wrapper │ │ ├── mod.esm.js │ │ └── package.json │ ├── lib │ │ └── XDGAppPaths.js │ ├── mod.cjs.d.ts │ ├── mod.cjs.js │ └── platform-adapters │ │ ├── _base.js │ │ └── node.js ├── esm │ ├── lib │ │ └── XDGAppPaths.js │ ├── mod.esm.js │ ├── package.json │ └── platform-adapters │ │ ├── _base.js │ │ └── node.js ├── types │ ├── mod.cjs.d.ts │ └── mod.d.ts └── xdg-app-paths.tgz ├── eg ├── show-paths.cjs.js ├── show-paths.esm.mjs ├── show-paths.local.deno.ts ├── show-paths.remote(CDN).deno.ts ├── show-paths.remote.deno.ts └── show-paths.ts ├── package.json ├── src ├── esm-wrapper │ ├── mod.esm.js │ └── package.json ├── lib │ └── XDGAppPaths.ts ├── mod.cjs.ts ├── mod.deno.ts ├── mod.esm.ts ├── mod.test.ts └── platform-adapters │ ├── _base.ts │ ├── deno.deno.ts │ └── node.ts ├── test ├── dist.test.js ├── fixtures │ ├── cli-display-name.cjs.js │ ├── cli-display-name.esm-wrapper.mjs │ ├── cli-display-name.esm.mjs │ ├── cli-display-name.ts │ └── cli-display-name.umd.js ├── integration.test.js ├── types.test-d.ts └── unit.test.js ├── tsconfig.json ├── tsconfig ├── tsconfig.cjs.json ├── tsconfig.eslint.json ├── tsconfig.esm.json ├── tsconfig.lab.json ├── tsconfig.types.json └── tsconfig.umd.json └── vendor ├── .gitattributes └── types └── deno.d.ts /.appveyor.yml: -------------------------------------------------------------------------------- 1 | # spell-checker:ignore repo 2 | 3 | version: '{build} ~ {branch}' 4 | 5 | branches: 6 | except: 7 | - gh-pages 8 | 9 | environment: 10 | matrix: 11 | - nodejs_version: '14' 12 | - nodejs_version: '12' 13 | - nodejs_version: '10' 14 | # - nodejs_version: '8' 15 | # - nodejs_version: '6' 16 | # - nodejs_version: "4" 17 | 18 | # platform: 19 | # - x86 20 | # - x64 21 | 22 | # Install scripts. (runs after repo cloning) 23 | install: 24 | # Get the latest stable version of Node.js or io.js 25 | # - ps: Install-Product node $env:nodejs_version $env:platform 26 | - ps: Install-Product node $env:nodejs_version 27 | # install modules 28 | - npm install 29 | 30 | # Post-install test scripts. 31 | test_script: 32 | # Output useful info for debugging. 33 | - node --version 34 | - npm --version 35 | # run tests 36 | - npm test 37 | 38 | # After successful build. 39 | on_success: 40 | # Post code coverage information 41 | - npm run coverage 42 | 43 | # Don't actually build. 44 | build: off 45 | -------------------------------------------------------------------------------- /.bmp.yml: -------------------------------------------------------------------------------- 1 | version: 8.3.0 2 | commit: '%.%.%' 3 | files: 4 | package.json: '"version": "%.%.%"' 5 | README.md: 6 | - 'git:github.com/rivy/js.xdg-app-paths#v%.%.%' 7 | - 'https://cdn.jsdelivr.net/gh/rivy/js.xdg-app-paths@v%.%.%' 8 | - 'https://deno.land/x/xdg_app_paths@v%.%.%' 9 | VERSION: '%.%.%' 10 | -------------------------------------------------------------------------------- /.changelog/CHANGELOG.tpl#mkd: -------------------------------------------------------------------------------- 1 | {{- /* */ -}} 2 | {{- /* # v2022-08-20 */ -}} 3 | 4 | {{- define "format-commit" -}} 5 | * {{ if .Scope }}{{ .Type | smartLowerFirstWord }} *({{ .Scope }})*: {{ .Subject | smartLowerFirstWord }}{{ else }}{{ .Header | smartLowerFirstWord }}{{ end }} ∾ [`{{ .Hash.Short }}`]({{ commitURL .Hash.Long }}) 6 | {{ end -}} 7 | 8 | {{- define "format-commit-group" }} 9 | #### {{ .Title }} 10 | 11 | {{ range .Commits }}{{ template "format-commit" . -}}{{ end -}} 12 | {{ end -}} 13 | 14 | 15 | 16 | 17 | 18 | 19 | # CHANGELOG
[{{ $.Info.Title }}]({{ $.Info.RepositoryURL }}) 20 | 21 |
22 | 23 | > This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 24 | >
25 | > The changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) using [conventional/semantic commits](https://nitayneeman.com/posts/understanding-semantic-commit-messages-using-git-and-angular).[`@`](https://archive.is/jnup8) 26 | 27 |
28 | 29 | {{- if .Unreleased.CommitGroups }} 30 | 31 | --- 32 | 33 | {{/* */ -}} 34 | ## [Unreleased] 35 | {{ range .Unreleased.CommitGroups }}{{ template "format-commit-group" . }}{{ end -}} 36 | {{ end }} 37 |
38 | {{- $first := true }}{{ range .Versions }} 39 | 40 | --- 41 | {{ $output := false -}} 42 | {{/* */}} 43 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }}) 44 | {{ if (index .Commits 0).Body }} 45 | {{ (index .Commits 0).Body }} 46 | {{ end }} 47 | [{{ .Tag.Name }}; details] 48 | {{ if .CommitGroups -}} 49 | {{ range .CommitGroups }}{{ if eq .Title "Features" }}{{ $output = true }}{{ template "format-commit-group" . }}{{- end -}}{{- end -}} 50 | {{ range .CommitGroups }}{{ if eq .Title "Enhancements" }}{{ $output = true }}{{ template "format-commit-group" . }}{{- end -}}{{- end -}} 51 | {{ range .CommitGroups }}{{ if eq .Title "Changes" }}{{ $output = true }}{{ template "format-commit-group" . }}{{- end -}}{{- end -}} 52 | {{ range .CommitGroups }}{{ if eq .Title "Fixes" }}{{ $output = true }}{{ template "format-commit-group" . }}{{- end -}}{{- end -}} 53 | {{ range .CommitGroups }}{{ if not (eq .Title "Features" "Enhancements" "Changes" "Fixes") }}{{ $output = true }}{{ template "format-commit-group" . }}{{- end -}}{{- end -}} 54 | {{- end -}} 55 | 56 | {{ if .RevertCommits }}{{ $output = true }} 57 | #### Reverts 58 | 59 | {{ range .RevertCommits -}} 60 | * {{ .Revert.Header }} 61 | {{ end -}} 62 | {{ end -}} 63 | 64 | {{ if .MergeCommits }}{{ $output = true }} 65 | #### Pull Requests 66 | 67 | {{ range .MergeCommits -}} 68 | * {{ .Header }} 69 | {{ end -}} 70 | {{ end -}} 71 | 72 | {{ if .NoteGroups -}}{{ $output = true }} 73 | {{ range .NoteGroups -}} 74 | #### {{ .Title }} 75 | 76 | {{ range .Notes }} 77 | {{- .Body }} 78 | {{ end -}} 79 | {{ end -}} 80 | {{ end -}} 81 | 82 | {{- if not $output }} 83 |
84 | 85 | *No changelog for this release.* 86 | {{ end }} 87 | 88 | {{- end -}} 89 |
90 | -------------------------------------------------------------------------------- /.changelog/config.yml: -------------------------------------------------------------------------------- 1 | # `git-changelog` configuration 2 | # ref: 3 | # v2022-08-20 4 | 5 | # spell-checker: ignore bugfix maint 6 | 7 | info: 8 | title: xdg-app-paths 9 | repository_url: https://github.com/rivy/js.xdg-app-paths 10 | style: github 11 | template: CHANGELOG.tpl#mkd 12 | options: 13 | commits: 14 | filters: 15 | Type: 16 | - change 17 | - docs 18 | - feat 19 | - fix 20 | - maint 21 | - perf 22 | - refactor 23 | - test 24 | - update 25 | # - version 26 | type_maps: 27 | # basic types (enables type match case-insensitivity) 28 | change: change 29 | docs: docs 30 | feat: feat 31 | fix: fix 32 | maint: maint 33 | perf: perf 34 | refactor: refactor 35 | test: test 36 | update: update 37 | # aggregating types 38 | add: change 39 | added: change 40 | bugfix: fix 41 | build: maint 42 | changed: change 43 | chore: maint 44 | deps: update 45 | fixed: fix 46 | fixes: fix 47 | tests: test 48 | updated: update 49 | upkeep: maint 50 | commit_groups: 51 | group_by: Type 52 | sort_by: Title 53 | title_maps: 54 | change: Changes 55 | docs: Documentation 56 | feat: Features 57 | fix: Fixes 58 | maint: Maintenance 59 | perf: Enhancements 60 | refactor: Refactoring 61 | test: Test Improvements 62 | update: Dependency Updates 63 | # version: Version Changes 64 | header: 65 | pattern: "^(\\w+)([!])\\s*[~:]?\\s(.*)$|^(\\w+)\\s*\\/(\\S+)\\s*[~:]?\\s(.*)$|^(\\w+)(?:\\s*\\(([^)]+)\\))?\\s*[~:]?\\s(.*)$" 66 | pattern_maps: 67 | - Type 68 | - Scope 69 | - Subject 70 | - Type 71 | - Scope 72 | - Subject 73 | - Type 74 | - Scope 75 | - Subject 76 | tag: 77 | # pattern: "^([RrVv](-[Vv]?)?)?\\d.*$" 78 | pattern: "^(?i)([v])?\\d.*$" 79 | notes: 80 | keywords: 81 | - BREAKING CHANGE 82 | -------------------------------------------------------------------------------- /.codacy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # CodeClimate configuration 3 | # ref: 4 | # v2002-07-18 [rivy] 5 | # note: use "Configuration file" setting in 'REPO/Code patterns/ESLint' and 'REPO/Code patterns/RemarkLint' 6 | 7 | # spell-checker:ignore (people) Roy Ivy III * rivy 8 | 9 | engines: 10 | duplication: 11 | exclude_paths: 12 | - 'eg/**' 13 | - 'tests/**' 14 | - '**.spec.js' 15 | - '**.spec.ts' 16 | - '**.test.js' 17 | - '**.test.ts' 18 | exclude_paths: 19 | - '.changelog/**' 20 | - 'CHANGELOG.mkd' 21 | - 'dist/**' 22 | - 'vendor/**' 23 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | # v2002-07-18 [rivy] 2 | # JavaScript/TypeScript 3 | # CodeClimate configuration; ref: https://docs.codeclimate.com/docs/advanced-configuration 4 | 5 | # spell-checker:ignore (names) EditorConfig MarkdownLint ShellCheck StyleLint (people) Roy Ivy III * rivy 6 | 7 | version: '2' # required to adjust maintainability checks 8 | checks: 9 | argument-count: 10 | config: 11 | threshold: 4 12 | complex-logic: 13 | config: 14 | threshold: 4 15 | file-lines: 16 | config: 17 | threshold: 250 18 | method-complexity: 19 | config: 20 | threshold: 20 ## default: 5 21 | method-count: 22 | config: 23 | threshold: 20 24 | method-lines: 25 | config: 26 | threshold: 40 ## default: 25 27 | nested-control-flow: 28 | config: 29 | threshold: 4 30 | return-statements: 31 | config: 32 | threshold: 4 33 | # similar-code: 34 | # config: 35 | # threshold: # has language-specific defaults; an override will affect all languages 36 | # identical-code: 37 | # config: 38 | # threshold: # has language-specific defaults; an override will affect all languages. 39 | 40 | plugins: 41 | duplication: 42 | enabled: true 43 | exclude_patterns: 44 | - 'eg/' 45 | - 'dist/' 46 | - 'vendor/' 47 | editorconfig: 48 | enabled: true 49 | # ref: https://docs.codeclimate.com/docs/eslint 50 | # * disabled; `eslint-plugin-import` fails and `eslint-plugin-functional` is not supported 51 | # eslint: 52 | # enabled: true 53 | # ref: https://docs.codeclimate.com/docs/markdownlint , https://github.com/markdownlint/markdownlint 54 | # * disabled; not configurable per-file/occurrence 55 | # markdownlint: 56 | # enabled: true 57 | shellcheck: 58 | enabled: true 59 | stylelint: 60 | enabled: true 61 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | informational: true 8 | changes: 9 | default: 10 | informational: true 11 | patch: 12 | default: 13 | informational: true 14 | -------------------------------------------------------------------------------- /.commitlint.config.js: -------------------------------------------------------------------------------- 1 | // CommitLint configuration 2 | // ref: 3 | // v2022-08-20 [rivy] 4 | 5 | // spell-checker:ignore (names) commitLint (people) Roy Ivy III * rivy (words) maint 6 | 7 | /* @prettier */ // note: (dprint) {.dprint.json}.prettier.associations should contain the name of this file 8 | 9 | const isNPMTestDist = !!process.env['npm_config_test_dist']; 10 | const isTestDist = !!process.env['test_dist']; 11 | const isTestRelease = !!process.env['test_release']; 12 | 13 | /** Relax linting rules/strictures (for development; *not* when submitting for distribution/release). */ 14 | const relaxedReview = !(isNPMTestDist || isTestDist || isTestRelease); 15 | 16 | const commitTags = [ 17 | 'Add', 18 | 'Added', 19 | 'Bugfix', 20 | 'Build', 21 | 'Change', 22 | 'Changed', 23 | 'Chore', 24 | 'Deps', 25 | 'Docs', 26 | 'Feat', 27 | 'Fix', 28 | 'Fixed', 29 | 'Fixes', 30 | 'FORK', 31 | 'Maint', 32 | 'Perf', 33 | 'Refactor', 34 | 'Style', 35 | 'Test', 36 | 'Tests', 37 | 'Update', 38 | 'Updated', 39 | 'Upkeep', 40 | // * git automated messages 41 | 'Automatic', 42 | 'Auto-merged', 43 | 'Merge', 44 | 'Merged', 45 | 'Revert', 46 | // * ok for relaxed review (ie, development), otherwise *not ok* 47 | ...(relaxedReview ? ['VERSION', 'WIP', 'X'] : []), 48 | ]; 49 | 50 | module.exports = { 51 | extends: ['@commitlint/config-conventional'], 52 | parserPreset: { 53 | parserOpts: { 54 | // headerPattern ~ tested at 55 | headerPattern: /^(\s*\w[\w-]*)(?:\s*(?:[/(]([\w,/]+)[)]?))?!?\s*[~:]?\s*(.*)$/, 56 | headerCorrespondence: ['type', 'scope', 'subject'], 57 | }, 58 | }, 59 | plugins: [ 60 | { 61 | rules: { 62 | '@local/DEBUG': (parsed, when, value) => { 63 | return [true, console.log({ parsed, when, value })]; 64 | }, 65 | }, 66 | }, 67 | ], 68 | // ref: [Commit messages starting with fixup! do not trigger any errors](https://github.com/conventional-changelog/commitlint/issues/3206) 69 | // ref: [tests for default ignores](https://github.com/conventional-changelog/commitlint/blob/914782aad70d353b/%40commitlint/is-ignored/src/defaults.ts#L20-L26) 70 | defaultIgnores: false, 71 | ignores: [ 72 | (msg) => msg.match(/^\s*\d+([.]\d+)*/) /* version commit */, 73 | relaxedReview 74 | ? (msg) => msg.match(/^\s*(fixup|squash)!/) /* fixup! or squash! commit */ 75 | : undefined, 76 | ].filter((v) => v != null), 77 | rules: { 78 | // '@local/DEBUG': [1, 'always'], 79 | 'body-max-line-length': [0], 80 | // ## maint [2020-01-07; rivy] ~ 'footer-leading-blank' disabled until is fixed 81 | // ## ... refs: , 82 | 'footer-leading-blank': [0], 83 | 'header-max-length': [1, 'always', 90], 84 | 'scope-case': [2, 'always', ['camel-case', 'lower-case', 'pascal-case', 'upper-case']], 85 | 'subject-case': [0], 86 | 'subject-empty': [relaxedReview ? 1 : 2, 'never'], 87 | 'type-case': [2, 'always', ['lower-case', 'sentence-case']], 88 | 'type-enum': [2, 'always', [...commitTags.map((v) => v.toLowerCase()), ...commitTags]], 89 | }, 90 | }; 91 | -------------------------------------------------------------------------------- /.deps-lock/.gitattributes: -------------------------------------------------------------------------------- 1 | # treat third-party code/tools directory as binary by default 2 | # * note: use `git diff --text ...` to override and show differences as text 3 | * binary 4 | .gitattributes !binary 5 | -------------------------------------------------------------------------------- /.ecrc.JS.json: -------------------------------------------------------------------------------- 1 | { 2 | "#": "EditorConfig-checker Config (for JS projects)", 3 | "#ref": "", 4 | "#version": "v2023-02-05 [rivy]", 5 | "#x-spell": "/* spell-checker:ignore (people) Roy Ivy III * rivy */", 6 | "Exclude": ["([._@#$]?build|[._@#$]?coverage|dist|target|vendor|[.]yarn)/.*"], 7 | "SpacesAfterTabs": true, 8 | "Disable": { "MaxLineLength": true } 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig (is awesome!; ref: http://EditorConfig.org) 2 | # ref: [EditorConfig ~ Level-0 Coding Standard](https://themightyprogrammer.dev/article/editor-config) @@ 3 | # v2022.07.30; rivy 4 | 5 | # spell-checker:ignore (people) Roy Ivy III * rivy (words) akefile makefile makefiles EOLs EOLNs MSVC NuShell POSIX VCproj 6 | 7 | # * top-most EditorConfig file 8 | root = true 9 | 10 | [*] 11 | # default ~ utf-8, unix-style newlines with a newline ending every file, 4 space indentation (and tab width) 12 | charset = utf-8 13 | end_of_line = lf 14 | indent_size = 4 15 | indent_style = space 16 | insert_final_newline = true 17 | max_line_length = 100 18 | smart_tabs = unset # ## unstable; ref: 19 | tab_width = unset # default to 'indent_size' 20 | trim_trailing_whitespace = true 21 | 22 | [{[Mm]akefile{,.*},*.{mak,mk,[Mm][Aa][Kk],[Mm][Kk]},[Gg][Nn][Uu]makefile}] 23 | # makefiles ~ TAB-style indentation 24 | indent_style = tab 25 | 26 | [*.{bash,sh}] 27 | # Linux/POSIX shell scripts 28 | indent_size = 4 29 | indent_style = space 30 | 31 | [*.{bat,cmd,[Bb][Aa][Tt],[Cc][Mm][Dd]}] 32 | # BAT/CMD ~ DOS/Win requires BAT/CMD files to have CRLF EOLNs 33 | end_of_line = crlf 34 | 35 | [*.{cjs,js,json,mjs,ts}] 36 | # js/ts ~ Prettier/XO-style == TAB indention + SPACE alignment 37 | indent_size = 2 38 | indent_style = tab 39 | smart_tabs = true # ## unstable; ref: 40 | 41 | [*.go] 42 | # go ~ TAB-style indentation (SPACE-style alignment); ref: @@ 43 | indent_style = tab 44 | smart_tabs = true # ## unstable; ref: 45 | 46 | [*.jq] 47 | # `jq` script files 48 | indent_size = 2 49 | indent_style = space 50 | 51 | [*.{markdown,md,mkd,[Mm][Dd],[Mm][Kk][Dd],[Mm][Dd][Oo][Ww][Nn],[Mm][Kk][Dd][Oo][Ww][Nn],[Mm][Aa][Rr][Kk][Dd][Oo][Ww][Nn]}] 52 | # markdown 53 | indent_size = 2 54 | indent_style = space 55 | 56 | [*.{nu,[Nn][Uu]}] 57 | # `nushell` script files · [NuShell]() 58 | indent_size = 2 59 | indent_style = space 60 | 61 | [*.{sln,vc{,x}proj{,.*},[Ss][Ln][Nn],[Vv][Cc]{,[Xx]}[Pp][Rr][Oo][Jj]{,.*}}] 62 | # MSVC sln/vcproj/vcxproj files, when used, will persistently revert to CRLF EOLNs and eat final EOLs 63 | end_of_line = crlf 64 | insert_final_newline = false 65 | 66 | [*.{yaml,yml,[Yy][Aa][Mm][Ll],[Yy][Mm][Ll]}] 67 | # YAML 68 | indent_size = 2 69 | indent_style = space 70 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // ESLint configuration 2 | // ref: 3 | // v2023-02-05 [rivy] 4 | 5 | // spell-checker:ignore (names) rivy ; (options) iife 6 | 7 | /* @prettier */ // note: (dprint) {.dprint.json}.prettier.associations should contain the name of this file 8 | 9 | const useDeno = true; 10 | const usePrettier = !useDeno; 11 | 12 | module.exports = { 13 | root: true, 14 | env: { es6: true }, 15 | ignorePatterns: [ 16 | '[._@#$]build', 17 | '[._@#$]coverage', 18 | '.eslintrc.js', 19 | '.nyc_output', 20 | '.yarn', 21 | 'build', 22 | 'coverage', 23 | 'dist', 24 | 'node_modules', 25 | 'vendor', 26 | ], 27 | parser: '@typescript-eslint/parser', 28 | // avoid `parserOptions` ~ [2020-10-29]/rivy ~ use is causing issues for eslint evaluation of files outside of `src` (see https://github.com/typescript-eslint/typescript-eslint/issues/1723) 29 | // parserOptions: { ecmaVersion: 6, project: ['./tsconfig.json', './tsconfig.eslint.json'] }, 30 | plugins: ['import', 'functional', '@typescript-eslint'], 31 | extends: [ 32 | 'eslint:recommended', 33 | 'plugin:@typescript-eslint/recommended', 34 | 'plugin:eslint-comments/recommended', 35 | 'plugin:functional/lite', 36 | 'plugin:import/typescript', 37 | 'plugin:security/recommended', 38 | 'plugin:security-node/recommended', 39 | ...(usePrettier ? ['prettier', 'prettier/@typescript-eslint'] : []), 40 | ], 41 | reportUnusedDisableDirectives: true, 42 | rules: { 43 | // ref: https://eslint.org/docs/rules 44 | '@typescript-eslint/explicit-module-boundary-types': 'off', 45 | '@typescript-eslint/no-unused-vars': [ 46 | 'error', 47 | { 48 | argsIgnorePattern: '^_', 49 | varsIgnorePattern: '^_', 50 | }, 51 | ], 52 | 'eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }], 53 | 'eslint-comments/no-unused-disable': 'warn', 54 | 'import/order': ['error', { 'newlines-between': 'always', alphabetize: { order: 'asc' } }], 55 | 'no-console': ['warn'], // ref: https://eslint.org/docs/rules/no-console 56 | 'no-restricted-syntax': [ 57 | 'error', 58 | { 59 | selector: `CallExpression[callee.object.name='console'][callee.property.name!=/^(log|warn|error|info|trace)$/]`, 60 | message: 'Unexpected property on console object was called', 61 | }, 62 | ], 63 | 'no-undefined': ['error'], // ref: https://eslint.org/docs/rules/no-undefined 64 | 'no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], // ref: https://eslint.org/docs/rules/no-unused-vars 65 | 'sort-imports': ['error', { ignoreDeclarationSort: true, ignoreCase: true }], 66 | 'wrap-iife': ['error', 'inside'], // correlate with Prettier formatting choice; ref: https://eslint.org/docs/rules/wrap-iife 67 | }, 68 | overrides: [{ files: ['*.js'], rules: { '@typescript-eslint/no-var-requires': 'off' } }], 69 | // globals: { BigInt: true, console: true, WebAssembly: true }, 70 | // globals: { Atomics: 'readonly', SharedArrayBuffer: 'readonly' }, 71 | }; 72 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # v2023.02.05 [rivy] 2 | # spell-checker:ignore (people) Roy Ivy III * rivy (words) deps EOLs MSVC 3 | 4 | # default; use LF EOLs for text files 5 | * text=auto eol=lf 6 | 7 | # CRLF required; force required CRLF EOLs for WinOS BAT/CMD and MSVC SLN files 8 | *.[bB][aA][tT] text eol=crlf 9 | *.[cC][mM][dD] text eol=crlf 10 | *.[sS][lL][nN] text eol=crlf 11 | 12 | # binaries; force binary interpretation (for diff sanity and avoidance of CRLF/LF issues) 13 | # * `yarn` config files; ref: @@ 14 | .yarn/**/* binary 15 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | # v2022-07-13 [rivy] 4 | # spell-checker:ignore (names) MacOS deps ; (people) Roy Ivy III * rivy 5 | 6 | on: [push] 7 | 8 | jobs: 9 | build: 10 | name: Build 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | os: [macos-latest, ubuntu-latest, windows-latest] 16 | node-version: [10.x, 12.x, 14.x, 16.x, 18.x] 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - run: npm install 25 | - run: npm run show:deps 26 | - run: npm run build --if-present 27 | - run: npm test 28 | env: 29 | CI: true 30 | - run: npm run coverage "--cov-send=--flags=${{ matrix.os }}" 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # v2023-02-04 [rivy] 2 | # spell-checker:ignore (people) Roy Ivy III * rivy (words) globstar 3 | 4 | # NOTE: Git GLOBSTAR syntax [see `git help gitignore`] 5 | # * ref: [.gitignore] http://git-scm.com/docs/gitignore @@ http://archive.is/Rk6rO 6 | # * ref: [Generate a 'gitignore'](https://gitignore.io) ; eg, 7 | 8 | # ignore intermediate/undistributed build artifacts 9 | build 10 | [._@#$]build 11 | target 12 | 13 | # ignore coverage data 14 | coverage 15 | [._@#$]coverage 16 | .nyc_output 17 | 18 | # ignore JS import/package-related files 19 | node_modules 20 | package-lock.json 21 | yarn.lock 22 | # * allow packaging of lock files into '.deps-lock' 23 | !.deps-lock/package-lock.json 24 | !.deps-lock/yarn.lock 25 | 26 | # ignore `yarn`-related files (allows use of "modern" v2+ `yarn`) 27 | # * ref: @@ 28 | .pnp.* 29 | .yarn/* 30 | !.yarn/patches 31 | !.yarn/plugins 32 | !.yarn/releases 33 | !.yarn/sdks 34 | !.yarn/versions 35 | # * use `.yarnrc.yml` for `yarn` config 36 | .yarnrc 37 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # no need for package-lock for a library 2 | package-lock=false 3 | # suppress occasional annoying npm update messages 4 | update-notifier=false 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Prettier "ignore" list 2 | # v2023-02-05 [rivy] 3 | # * note: glob patterns support use of `?`, `*`, `**`, and `[...]`, but *not* `{...}` 4 | 5 | # spell-checker:ignore (people) Roy Ivy III * rivy 6 | 7 | # * build/coverage/dev artifacts 8 | [._@#$]build 9 | [._@#$]coverage 10 | .nyc_output 11 | build 12 | coverage 13 | CHANGELOG 14 | CHANGELOG.* 15 | dist 16 | target 17 | 18 | # * format-sensitive files 19 | .changelog/*.tpl 20 | .changelog/*.tpl.* 21 | 22 | # * third-party code 23 | **/node_modules 24 | **/*-lock.json 25 | .history 26 | .vscode 27 | .yarn 28 | package.json 29 | vendor 30 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | // Prettier configuration 2 | // ref: 3 | // v2022-08-20 [rivy] 4 | 5 | // spell-checker:ignore (people) Roy Ivy III * rivy 6 | 7 | /* @prettier */ // note: (dprint) {.dprint.json}.prettier.associations should contain the name of this file 8 | 9 | module.exports = { 10 | // $schema: 'http://json.schemastore.org/prettierrc', 11 | printWidth: 100, 12 | proseWrap: 'preserve', 13 | singleQuote: true, 14 | tabWidth: 2, 15 | useTabs: true, 16 | // ## overrides/[*.markdown]/tabWidth": "// set this to 4 when/if https://github.com/prettier/prettier/issues/5019 is fixed", 17 | overrides: [{ files: ['*.md', '*.mkd', '*.markdown'], options: { tabWidth: 2, useTabs: false } }], 18 | }; 19 | -------------------------------------------------------------------------------- /.remarkrc.js: -------------------------------------------------------------------------------- 1 | // remark configuration (ref: ) 2 | // ref: 3 | // v2022-08-20 [rivy] 4 | 5 | // spell-checker:ignore (people) Roy Ivy III * rivy (words) frontmatter retext 6 | 7 | /* @prettier */ // note: (dprint) {.dprint.json}.prettier.associations should contain the name of this file 8 | 9 | exports.plugins = [ 10 | require('remark-footnotes'), 11 | // require('remark-frontmatter'), 12 | [ 13 | require('remark-retext'), 14 | require('unified')().use({ 15 | plugins: [ 16 | require('retext-english'), 17 | require('retext-syntax-urls'), 18 | // [require('retext-spell'), require('dictionary-en')], 19 | [require('retext-sentence-spacing'), { preferred: 1 }], 20 | require('retext-repeated-words'), 21 | require('retext-passive'), 22 | ], 23 | }), 24 | ], 25 | 'remark-preset-lint-consistent', 26 | 'remark-preset-lint-recommended', 27 | 'remark-preset-lint-markdown-style-guide', 28 | ['remark-lint-emphasis-marker', 'consistent'], 29 | ['remark-lint-file-extension', false], 30 | ['remark-lint-heading-increment', false], 31 | ['remark-lint-list-item-indent', 'mixed'], 32 | ['remark-lint-list-item-spacing', false], 33 | ['remark-lint-maximum-heading-length', false], 34 | ['remark-lint-maximum-line-length', false], 35 | ['remark-lint-no-duplicate-headings', false], 36 | ['remark-lint-unordered-list-marker-style', 'consistent'], 37 | ]; 38 | -------------------------------------------------------------------------------- /.rollup.config.types.js: -------------------------------------------------------------------------------- 1 | // `rollup` configuration 2 | // ref: 3 | // v2002-07-14 [rivy] 4 | // setup: `npm i rollup @rollup/plugin-typescript` or `npm i rollup rollup-plugin-typescript2` (for visible TS error output) 5 | 6 | // spell-checker:ignore (people) Roy Ivy III * rivy 7 | 8 | import dts from 'rollup-plugin-dts'; 9 | 10 | export default [ 11 | // bundle TypeScript typings (TypeScript is unable/unwilling to do so...) 12 | // * ref: , 13 | // * ref: 14 | { 15 | input: './build/types/src/mod.esm.d.ts', 16 | output: [{ file: './dist/types/mod.d.ts', format: 'esm' }], 17 | plugins: [dts()], 18 | }, 19 | { 20 | input: './build/types/src/mod.cjs.d.ts', 21 | output: [{ file: './dist/types/mod.cjs.d.ts', format: 'cjs' }], 22 | plugins: [dts()], 23 | // * note: for correct interpretation of types by VSCode, './dist/types/mod.cjs.d.ts' requires a subsequent text replacement ("export { _default as default }" => "export = _default") 24 | }, 25 | ]; 26 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | # JavaScript/TypeScript (NodeJS-v10+) 2 | # ref: https://scrutinizer-ci.com/docs/configuration/build_reference 3 | # spell-checker:ignore () eqeqeq 4 | build: 5 | environment: 6 | node: v10.14.2 7 | nodes: 8 | analysis: 9 | tests: 10 | override: 11 | - js-scrutinizer-run 12 | 13 | checks: 14 | javascript: 15 | no_implicit_undefined_return: true 16 | no_else_return: true 17 | no_alert: true 18 | eqeqeq: true 19 | no_loop_var_assign: true 20 | no_param_assign: true 21 | no_var: true 22 | 23 | filter: 24 | dependency_paths: 25 | - 'node_modules/' 26 | excluded_paths: 27 | - 'dist/' 28 | - 'src/types/' 29 | - 'test/' 30 | - 'vendor/' 31 | - '*.spec.js' 32 | - '*.spec.ts' 33 | - '*.test.js' 34 | - '*.test.ts' 35 | -------------------------------------------------------------------------------- /.vscode/cspell.dictionaries/acronyms+names.wordlist.txt: -------------------------------------------------------------------------------- 1 | # * abbreviations / acronyms 2 | AST # abstract syntax tree 3 | CICD # continuous integration/deployment 4 | CPU 5 | CPUs 6 | DevOps 7 | EOF 8 | EOL 9 | EOLN 10 | FIFO 11 | FIFOs 12 | FOSS # free open source software 13 | FQDN # fully qualified domain name 14 | GID # group ID 15 | GIDs 16 | GNUEABI 17 | GNUEABIhf 18 | MSVC 19 | MSRV # minimum supported rust version 20 | OSS # open source software 21 | POSIX 22 | POSIXLY 23 | RISC 24 | RISCV 25 | RNG # random number generator 26 | RNGs 27 | UID # user ID 28 | UIDs 29 | UUID # universally unique identifier 30 | WASI 31 | WASM 32 | aarch 33 | flac 34 | lzma 35 | 36 | # * names 37 | BusyBox 38 | Codacy 39 | Cygwin 40 | Deno 41 | Dprint 42 | EditorConfig 43 | FreeBSD 44 | Gmail 45 | Irix 46 | JSDelivr 47 | MS-DOS 48 | MSDOS 49 | MacOS 50 | MinGW 51 | Minix 52 | NetBSD 53 | Novell 54 | npmJS 55 | NuShell 56 | OpenBSD 57 | POSIX 58 | PowerPC 59 | SELinux 60 | SkyPack 61 | Solaris 62 | SysV 63 | Xenix 64 | Yargs 65 | -------------------------------------------------------------------------------- /.vscode/cspell.dictionaries/jargon.wordlist.txt: -------------------------------------------------------------------------------- 1 | arity 2 | autogenerate 3 | autogenerated 4 | autogenerates 5 | bitmask 6 | bitrot 7 | canonicalization 8 | canonicalize 9 | colorizable 10 | colorize 11 | committish 12 | cyclomatic 13 | dedup 14 | demangle 15 | denoland 16 | deque 17 | dequeue 18 | discoverability 19 | duplicative 20 | enqueue 21 | executable 22 | executables 23 | falsey 24 | flamegraph 25 | gibibytes 26 | glob 27 | globbed 28 | globbing 29 | hardfloat 30 | hardlink 31 | hardlinks 32 | hashsums 33 | kibi 34 | kibibytes 35 | mebi 36 | mebibytes 37 | mergeable 38 | multibyte 39 | nonportable 40 | peekable 41 | performant 42 | polyfill 43 | ponyfill 44 | precompiled 45 | precompute 46 | preload 47 | prepend 48 | prepended 49 | primality 50 | pseudoprime 51 | pseudoprimes 52 | readonly 53 | regen 54 | reparse 55 | seedable 56 | semver 57 | shortcode 58 | shortcodes 59 | stringify 60 | stringification 61 | symlink 62 | symlinks 63 | syscall 64 | syscalls 65 | tokenize 66 | transpile 67 | transpilation 68 | truthy 69 | unbuffered 70 | unportable 71 | vendored 72 | whitespace 73 | wordlist 74 | wordlists 75 | 76 | # * abbreviations 77 | consts 78 | deps 79 | dev 80 | eval 81 | maint 82 | procs 83 | -------------------------------------------------------------------------------- /.vscode/cspell.dictionaries/people.wordlist.txt: -------------------------------------------------------------------------------- 1 | Dimitri Benin * BendingBender 2 | Oden * ops991923 3 | Roy Ivy III * rivy 4 | Selwyn * siilwyn 5 | Simon Kjellberg * simon.kjellberg 6 | Sindre Sorhus * SindreSorhus 7 | -------------------------------------------------------------------------------- /.vscode/cspell.dictionaries/shell.wordlist.txt: -------------------------------------------------------------------------------- 1 | # * POSIX 2 | TMPDIR 3 | csh 4 | globstar 5 | nullglob 6 | passwd 7 | pipefail 8 | popd 9 | pushd 10 | sh 11 | tcsh 12 | zsh 13 | 14 | # * Windows 15 | APPDATA 16 | COMSPEC 17 | HKCU 18 | HKLM 19 | HOMEDRIVE 20 | HOMEPATH 21 | LOCALAPPDATA 22 | PATHEXT 23 | PATHEXT 24 | SYSTEMROOT 25 | USERDOMAIN 26 | USERNAME 27 | USERPROFILE 28 | 29 | # * `git` 30 | gitattributes 31 | gitignore 32 | 33 | # * `make` (`gmake`) 34 | CURDIR 35 | GNUMAKEFLAGS 36 | GNUMakefile 37 | LIBPATTERNS 38 | MAKECMDGOALS 39 | MAKEFILES 40 | MAKEFLAGS 41 | MAKELEVEL 42 | MAKESHELL 43 | SHELLSTATUS 44 | VPATH 45 | abspath 46 | addprefix 47 | addsuffix 48 | endef 49 | firstword 50 | ifeq 51 | ifneq 52 | lastword 53 | notdir 54 | patsubst 55 | 56 | # * `npm` 57 | corepack 58 | preversion 59 | 60 | # * `prettier` 61 | prettierignore 62 | 63 | # * utilities 64 | chglog 65 | commitlint 66 | dprint 67 | gcov 68 | gmake 69 | grcov 70 | grep 71 | markdownlint 72 | mkdir 73 | rimraf 74 | rollup 75 | sed 76 | stty 77 | typedoc 78 | xargs 79 | -------------------------------------------------------------------------------- /.vscode/cspell.json: -------------------------------------------------------------------------------- 1 | // `cspell` configuration/settings 2 | // ref: 3 | // v2022.08.09 [rivy] 4 | { 5 | "version": "0.2", // configuration/settings file version 6 | "language": "en", // language - current active spelling language 7 | "dictionaries": ["#local", "acronyms+names", "jargon", "people", "shell", "workspace"], 8 | "dictionaryDefinitions": [ 9 | { "name": "#local", "path": "./cspell.dictionaries/#local-only.wordlist.txt" }, 10 | { "name": "acronyms+names", "path": "./cspell.dictionaries/acronyms+names.wordlist.txt" }, 11 | { "name": "jargon", "path": "./cspell.dictionaries/jargon.wordlist.txt" }, 12 | { "name": "people", "path": "./cspell.dictionaries/people.wordlist.txt" }, 13 | { "name": "shell", "path": "./cspell.dictionaries/shell.wordlist.txt" }, 14 | { "name": "workspace", "path": "./cspell.dictionaries/workspace.wordlist.txt" } 15 | ], 16 | // ignorePaths - a list of globs to specify which files are to be ignored 17 | "ignorePaths": ["{,.,_,#,@}build/**", "{,.,_,#,@}coverage/**", "{,.,_,#,@}target/**", "tests/**/fixtures/**", "vendor/**"], 18 | // ignoreWords 19 | "ignoreWords": [], 20 | // words - list of words to be always considered correct 21 | "words": [] 22 | } 23 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "davidanson.vscode-markdownlint", 8 | "dbaeumer.vscode-eslint", 9 | "editorconfig.editorconfig", 10 | "esbenp.prettier-vscode", 11 | "streetsidesoftware.code-spell-checker" 12 | ], 13 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 14 | "unwantedRecommendations": [ 15 | "dbaeumer.jshint", 16 | "hookyqr.beautify" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[javascript]": { 3 | // "editor.defaultFormatter": "dprint.dprint" 4 | "editor.defaultFormatter": "esbenp.prettier-vscode" 5 | }, 6 | "[json]": { 7 | // "editor.defaultFormatter": "dprint.dprint" 8 | "editor.defaultFormatter": "esbenp.prettier-vscode" 9 | }, 10 | "[jsonc]": { 11 | // "editor.defaultFormatter": "dprint.dprint" 12 | "editor.defaultFormatter": "esbenp.prettier-vscode" 13 | }, 14 | "[typescript]": { 15 | // "editor.defaultFormatter": "dprint.dprint" 16 | "editor.defaultFormatter": "esbenp.prettier-vscode" 17 | }, 18 | "deno.enable": false, 19 | "editor.formatOnSave": true, 20 | "files.exclude": { 21 | "**/.git": true, 22 | "**/.svn": true, 23 | "**/.hg": true, 24 | "**/CVS": true, 25 | "**/.DS_Store": true, 26 | "node_modules": true, 27 | ".history": true, 28 | ".nyc_output": true 29 | }, 30 | "indentRainbow.ignoreLinePatterns": [ 31 | "/[\t]+[ ]/g" // TAB indentaion with space alignment 32 | // "/[ \t]* [*]/g", 33 | // "/[ \t]+[/]{2}/g" 34 | ], 35 | "todo-tree.filtering.excludeGlobs": [ 36 | "build", 37 | "dist", 38 | "vendor" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | yarn-path ".yarn/releases/yarn-1.22.19.cjs" 6 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | enableGlobalCache: true 2 | 3 | logFilters: 4 | - code: YN0032 5 | level: discard 6 | - code: YN0061 7 | level: discard 8 | 9 | nodeLinker: node-modules 10 | 11 | yarnPath: .yarn/releases/yarn-1.22.19.cjs 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Roy Ivy III 4 | Copyright (c) Sindre Sorhus (sindresorhus.com) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | # [xdg-app-paths](https://github.com/rivy/js.xdg-app-paths) 20 | 21 | > Determine ([XDG](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)-compatible) paths for storing application files (cache, config, data, etc) 22 | 23 | [![Build status (GHA)][gha-image]][gha-url] 24 | [![Build status (AppVeyor)][appveyor-image]][appveyor-url] 25 | [![Coverage status][coverage-image]][coverage-url] 26 | [![License][license-image]][license-url] 27 | [![Style Guide][style-image]][style-url] 28 |  
29 | [![Repository][repository-image]][repository-url] 30 | [![Deno version][deno-image]][deno-url] 31 | [![NPM version][npm-image]][npm-url] 32 | [![NodeJS version][nodejsv-image]][repository-url] 33 | [![npmJS Downloads][downloads-image]][downloads-url] 34 | [![JSDelivr Downloads][jsdelivr-image]][jsdelivr-url] 35 | 36 | 44 | 45 | ## Installation (CJS/ESM/TypeScript) 46 | 47 | 48 | 49 | ```shell 50 | npm install xdg-app-paths 51 | # or... `npm install "git:github.com/rivy/js.xdg-app-paths"` 52 | # or... `npm install "git:github.com/rivy/js.xdg-app-paths#v8.3.0"` 53 | # or... `npm install "https://cdn.jsdelivr.net/gh/rivy/js.xdg-app-paths@v8.3.0/dist/xdg-app-paths.tgz"` 54 | # or... `npm install "https://cdn.jsdelivr.net/gh/rivy/js.xdg-app-paths@COMMIT_SHA/dist/xdg-app-paths.tgz"` 55 | ``` 56 | 57 | ## Usage 58 | 59 | #### CommonJS (CJS) 60 | 61 | ```js 62 | // MyApp.js 63 | const xdgAppPaths = require('xdg-app-paths/cjs'); 64 | 65 | const cache = xdgAppPaths.cache(); 66 | //(nix)=> '/home/rivy/.cache/MyApp.js' 67 | //(win)=> 'C:\\Users\\rivy\\AppData\\Local\\MyApp\\Cache' 68 | 69 | const config = xdgAppPaths.config(); 70 | //(nix)=> '/home/rivy/.config/MyApp.js' 71 | //(win)=> 'C:\\Users\\rivy\\AppData\\Roaming\\MyApp\\Config' 72 | 73 | const data = xdgAppPaths.data(); 74 | //(nix)=> '/home/rivy/.local/share/MyApp.js' 75 | //(win)=> 'C:\\Users\\rivy\\AppData\\Roaming\\MyApp\\Data' 76 | ``` 77 | 78 | #### ECMAScript (ESM)/TypeScript 79 | 80 | ```js 81 | import xdgAppPaths from 'xdg-app-paths'; 82 | const configDirs = xdgAppPaths.configDirs(); 83 | //... 84 | ``` 85 | 86 | #### Deno 87 | 88 | 89 | 90 | ```ts 91 | import xdgAppPaths from 'https://deno.land/x/xdg_app_paths@v8.3.0/src/mod.deno.ts'; 92 | //or (via CDN, [ie, JSDelivr with GitHub version/version-range, commit, 'latest' support])... 93 | //import xdgAppPaths from 'https://cdn.jsdelivr.net/gh/rivy/js.xdg-app-paths@v8.3.0/src/mod.deno.ts'; 94 | //import xdgAppPaths from 'https://cdn.jsdelivr.net/gh/rivy/js.xdg-app-paths@COMMIT_SHA/src/mod.deno.ts'; 95 | const configDirs = xdgAppPaths.configDirs(); 96 | //... 97 | ``` 98 | 99 | ## API 100 | 101 | ### Construction/Initialization 102 | 103 | #### `XDGAppPaths( Options? )` 104 | 105 | ```js 106 | // CJS 107 | const xdgAppPaths = require('xdg-app-paths/cjs'); 108 | // or ... 109 | const xdgAppPaths = require('xdg-app-paths/cjs')(options); 110 | 111 | // ESM/TypeScript 112 | import xdgAppPaths from 'xdg-app-paths'; 113 | // or ... 114 | import XDGAppPaths from 'xdg-app-paths'; 115 | const xdgAppPaths = XDGAppPaths(options); 116 | 117 | // Deno 118 | import xdgAppPaths from 'https://deno.land/x/xdg_app_paths/src/mod.deno.ts'; 119 | // or ... 120 | import XDGAppPaths from 'https://deno.land/x/xdg_app_paths/src/mod.deno.ts'; 121 | const xdgAppPaths = XDGAppPaths(options); 122 | ``` 123 | 124 | When importing this module, the object returned is a function object, `XDGAppPaths`, augmented with attached methods. Additional `XDGAppPaths` objects may be constructed by direct call of the imported `XDGAppPaths` object (eg, `const x = xdgAppPaths(...)`) or by using `new` (eg, `const x = new xdgAppPaths(...)`). 125 | 126 | Upon construction, if not supplied with a specified name (via `Options.name`), `XDGAppPaths` will generate an application name which is used to further generate isolated application directories, where needed. "$eval" is used as the fallback value when automatically generating names (ie, for immediate mode scripts such as `node -e "..."`). The generated or supplied name is stored during `XDGAppPaths` construction and subsequently accessible via the `$name()` method. 127 | 128 | ### Interfaces/Types 129 | 130 | ```js 131 | import type { DirOptions, Options, XDGAppPaths } from 'xdg-app-paths'; // TypeScript 132 | //or... 133 | //import type { DirOptions, Options, XDGAppPaths } from 'https://deno.land/x/xdg_app_paths/src/mod.deno.ts'; // Deno 134 | ``` 135 | 136 | #### `XDGAppPaths` 137 | 138 | _`XDGAppPaths` API; also, the interface/type of the default function object export_ 139 | 140 | --- 141 | 142 | #### `DirOptions` 143 | 144 | _Configuration options supplied to `XDGAppPaths` methods_ 145 | 146 | 147 | 148 | > **`DirOptions: boolean` => `{ isolated: boolean }`**
As a shortcut, when `DirOptions` is supplied as a `boolean`, it is directly interpreted as the `isolated` property (ie, `dirOptions = { isolated: dirOptions }`). 149 | > 150 | > --- 151 | > 152 | > **`DirOptions: object`**
• default = `{ isolated: true }` 153 | > 154 | > **`DirOptions.isolated: boolean`**
• default = `true`
_Isolation flag; used to override the default isolation mode, when needed_ 155 | 156 |
157 | 158 | #### `Options` 159 | 160 | _Configuration options supplied when constructing `XDGAppPaths`_ 161 | 162 | 163 | 164 | > **`Options: string` => `{ name: string }`**
As a shortcut, when `Options` is supplied as a `string`, is interpreted directly as the `name` property (ie, `options = { name: options }`). 165 | > 166 | > --- 167 | > 168 | > **`Options: object`**
• default = `{ name: '', suffix: '', isolated: true }` 169 | > 170 | > **`Options.name: string`**
• default = `''`
_Name of the application; used to generate isolated application paths_
When missing (`undefined`, `null`, or empty (`''`)), it is generated automatically from the process main file name, where determinable. `'$eval'` is used as a final fallback value when the application name cannot otherwise be determined. Note, Deno reports `'$deno$eval'` as the main file name when executing `deno eval ...`. 171 | > 172 | > **`Options.suffix: string`**
• default = `''`
_Suffix which is appended to the application name when generating the application paths_ 173 | > 174 | > **`Options.isolated: boolean`**
• default = `true`
_Default isolation flag (used when no isolation flag is supplied for `DirOptions`)_ 175 | 176 |
177 | 178 | All interfaces/types listed are exported individually by name (eg, as "XDGAppPaths"). 179 | 180 | ### Methods 181 | 182 | All returned path strings are simple, platform-compatible, strings and are _not_ guaranteed to exist. The application is responsible for construction of the directories. If needed, [`make-dir`](https://www.npmjs.com/package/make-dir) or [`mkdirp`](https://www.npmjs.com/package/mkdirp) can be used to create the directories. 183 | 184 | #### `xdgAppPaths.cache( DirOptions? ): string` 185 | 186 | _Returns the directory for non-essential data files_ 187 | 188 | > Deletion of the data contained here might cause an application to slow down. 189 | 190 | #### `xdgAppPaths.config( DirOptions? ): string` 191 | 192 | _Returns the directory for config files_ 193 | 194 | > Deletion of the data contained here might require the user to reconfigure an application. 195 | 196 | #### `xdgAppPaths.data( DirOptions? ): string` 197 | 198 | _Returns the directory for data files_ 199 | 200 | > Deletion of the data contained here might force the user to restore from backups. 201 | 202 | #### `xdgAppPaths.runtime( DirOptions? ): string?` 203 | 204 | _Returns the directory for runtime files; may return `undefined`_ 205 | 206 | > Deletion of the data contained here might interfere with a currently executing application but should have no effect on future executions. 207 | 208 | #### `xdgAppPaths.state( DirOptions? ): string` 209 | 210 | _Returns the directory for state files_ 211 | 212 | > Deletion of the data contained here should not materially interfere with execution of an application. 213 | 214 | #### `xdgAppPaths.configDirs( DirOptions? ): readonly string[]` 215 | 216 | _Returns a priority-sorted list of possible directories for configuration file storage (includes `paths.config()` as the first entry)_ 217 | 218 | #### `xdgAppPaths.dataDirs( DirOptions? ): readonly string[]` 219 | 220 | _Returns a priority-sorted list of possible directories for data file storage (includes `paths.data()` as the first entry)_ 221 | 222 | #### `xdgAppPaths.$name(): string` 223 | 224 | _Application name used for path construction (from supplied configuration or auto-generated)_ 225 | 226 | #### `xdgAppPaths.$isolated(): boolean` 227 | 228 | _Default isolation mode used by the particular `XDGAppPaths` instance_ 229 | 230 | ## Example 231 | 232 | ```js 233 | // MyApp.js 234 | const locatePath = require('locate-path'); 235 | const mkdirp = require('mkdirp'); 236 | const path = require('path'); 237 | 238 | const xdgAppPaths = require('xdg-app-paths/cjs'); 239 | // Extend appPaths with a "log" location function 240 | xdgAppPaths.log = function (dirOptions) { 241 | const self = xdgAppPaths; // * bind `self` to `xdgAppPaths` => avoids `this` variability due to caller context 242 | function typeOf(x) { 243 | // use avoids circumvention of eslint variable tracking for `x` 244 | return typeof x; 245 | } 246 | 247 | if (typeOf(dirOptions) === 'boolean') { 248 | dirOptions = { isolated: dirOptions }; 249 | } 250 | 251 | if ( 252 | typeOf(dirOptions) !== 'object' || 253 | dirOptions === null || 254 | typeOf(dirOptions.isolated) !== 'boolean' 255 | ) { 256 | dirOptions = { isolated: self.$isolated() }; 257 | } 258 | 259 | return path.join(self.state(dirOptions), (dirOptions.isolated ? '' : self.$name() + '-') + 'log'); 260 | }; 261 | 262 | // log file 263 | const logPath = path.join(xdgAppPaths.log(), 'debug.txt'); 264 | mkdirp.sync(path.dirname(logPath), 0o700); 265 | 266 | // config file 267 | // * search for config file within user preferred directories; otherwise, use preferred directory 268 | const possibleConfigPaths = xdgAppPaths 269 | .configDirs() 270 | .concat(xdgAppPaths.configDirs({ isolated: !xdgAppPaths.$isolated() })) 271 | .map((v) => path.join(v, xdgAppPaths.$name() + '.json')); 272 | const configPath = locatePath.sync(possibleConfigPaths) || possibleConfigPaths[0]; 273 | // debug(logPath, 'configPath="%s"', configPath); 274 | mkdirp.sync(path.dirname(configPath), 0o700); 275 | 276 | // cache file 277 | const cacheDir = path.join(xdgAppPaths.cache()); 278 | // debug(logPath, 'cacheDir="%s"', cacheDir); 279 | mkdirp.sync(cacheDir, 0o700); 280 | const cachePath = {}; 281 | cachePath.orders = path.join(cacheDir, 'orders.json'); 282 | cachePath.customers = path.join(cacheDir, 'customers.json'); 283 | //... 284 | ``` 285 | 286 | ## Supported Platforms 287 | 288 | ### NodeJS 289 | 290 | > #### Requirements 291 | > 292 | > NodeJS >= 4.0[^*] 293 | 294 | 295 | 296 | [^*]: With the conversion to a TypeScript-based project, due to tooling constraints, building and testing are more difficult and more limited on Node platforms earlier than NodeJS-v10. However, the generated CommonJS/UMD project code is fully tested (for NodeJS-v10+) and continues to be compatible with NodeJS-v4+. 297 | 298 | #### CommonJS modules (CJS; `*.js` and `*.cjs`) 299 | 300 | CJS is the basic supported output (with support for NodeJS versions as early as NodeJS-v4). 301 | 302 | ```js 303 | const xdgAppPaths = require('xdg-app-paths/cjs'); 304 | console.log(xdgAppPaths.config()); 305 | ``` 306 | 307 | > Note: for CJS, `require('xdg-app-paths')` is supported for backward-compatibility and will execute correctly at run-time. However, `require('xdg-app-paths')` links to the default package type declarations which, though _correct_ for Deno/ESM/TypeScript, are _incorrect_ for CJS. This, then, leads to incorrect analysis of CJS files by static analysis tools such as TypeScript and Intellisense. 308 | > 309 | > Using `require('xdg-app-paths/cjs')` is preferred as it associates the proper CJS type declarations and provides correct information to static analysis tools. 310 | 311 | #### ECMAScript modules (ESM; `*.mjs`) 312 | 313 | - Requires `XDGAppPaths` `v6.0`+. 314 | 315 | `XDGAppPaths` fully supports ESM imports. 316 | 317 | ```js 318 | import xdgAppPaths from 'xdg-app-paths'; 319 | console.log(xdgAppPaths.config()); 320 | ``` 321 | 322 | ### TypeScript (`*.ts`) 323 | 324 | - Requires `XDGAppPaths` `v6.0`+. 325 | 326 | As of `v6.0`+, `XDGAppPaths` has been converted to a TypeScript-based module. 327 | As a consequence, TypeScript type definitions are automatically generated, bundled, and exported by the module. 328 | 329 | ### Deno 330 | 331 | > #### Requirements 332 | > 333 | > Deno >= v1.8.0[^deno-version-req] 334 | 335 | 336 | 337 | [^deno-version-req]: The `Deno.permissions` API (stabilized in Deno v1.8.0) is required to avoid needless panics or prompts by Deno during static imports of this module/package. Note: Deno v1.3.0+ may be used if the run flag `--unstable` is also used. 338 | 339 | > #### Required Permissions 340 | > 341 | > - `--allow-env` · _allow access to the process environment variables_
342 | > This is a transitive requirement from the 'xdg'/'xdg-portable' module; `XDG` requires access to various environment variable to determine platform and user configuration (eg, XDG configuration variables, location of temp and user directories, ...). 343 | > - `--allow-read` · _allow read(-only) access to the file system_
344 | > This permission is required to use `Deno.mainModule`, which is, in turn, required to auto-generate the application name used for data isolation. 345 | 346 | 347 | 348 | - Requires `XDGAppPaths` `v7.0`+. 349 | 350 | `XDGAppPaths` also fully supports use by Deno. 351 | 352 | ```js deno 353 | import xdgAppPaths from 'https://deno.land/x/xdg_app_paths/src/mod.deno.ts'; 354 | console.log(xdgAppPaths.config()); 355 | ``` 356 | 357 | ## Discussion 358 | 359 | The [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)­[@](https://archive.is/J0mTC) defines categories of user information (ie, "cache", "config", "data", ...), defines their standard storage locations, and defines the standard process for user configuration of those locations (using `XDG_CACHE_HOME`, etc). 360 | 361 | Applications supporting the XDG convention are expected to store user-specific files within these locations, either within the common/shared directory (eg, `` `${xdg.cache()}/filename` ``) or within a more isolated application-defined subdirectory (eg, `` `${xdg.config()}/DIR/filename` ``; `DIR` usually being the application name). 362 | 363 | ### Windows ("win32") specific notes 364 | 365 | Windows has an alternate convention, offering just two standard locations for applications to persist data, either `%APPDATA%` (for files which may "roam" with the user between hosts) and `%LOCALAPPDATA%` (for local-machine-only files). All application files are expected to be stored within an application-unique subdirectory in one of those two locations, usually under a directory matching the application name. There is no further popular convention used to segregate the file types (ie, into "cache", "config", ...) in any way similar to the XDG specification. 366 | 367 | So, to support basic XDG-like behavior (that is, segregating the information types into type-specific directories), this module supports a new convention for Windows hosts (taken from [`xdg-portable`](https://www.npmjs.com/package/xdg-portable)), placing the specific types of files into subdirectories under either `%APPDATA%` or `%LOCALAPPDATA%`, as appropriate for the file type. The default directories used for the windows platform are listed by [`xdg-portable`](https://www.npmjs.com/package/xdg-portable#api). 368 | 369 | By default, this module returns paths which are isolated, application-specific sub-directories under the respective common/shared base directories. These sub-directories are purely dedicated to use by the application. If, however, the application requires access to the common/shared areas, the `isolated: false` option may be used during initialization (or as an optional override for specific function calls) to generate and return the common/shared paths. Note, that when using the command/shared directories, take care to use file names which do not collide with those used by other applications. 370 | 371 | ### Origins 372 | 373 | This module was forked from [sindresorhus/env-paths](https://github.com/sindresorhus/env-paths) in order to add cross-platform portability and support simpler cross-platform applications. 374 | 375 | ## Building and Contributing 376 | 377 | [![Repository][repository-image]][repository-url] 378 | [![Build status (GHA)][gha-image]][gha-url] 379 | [![Build status (AppVeyor)][appveyor-image]][appveyor-url] 380 | [![Coverage status][coverage-image]][coverage-url] 381 |  
382 | [![Quality status (Codacy)][codacy-image]][codacy-url] 383 | [![Quality status (CodeClimate)][codeclimate-image]][codeclimate-url] 384 | [![Quality status (CodeFactor)][codefactor-image]][codefactor-url] 385 | 386 | ### Build requirements 387 | 388 | - NodeJS >= 10.14 389 | - a JavaScript package/project manager ([`npm`](https://www.npmjs.com/get-npm) or [`yarn`](https://yarnpkg.com)) 390 | - [`git`](https://git-scm.com) 391 | 392 | > #### optional 393 | > 394 | > - [`bmp`](https://deno.land/x/bmp@v0.0.6) (v0.0.6+) ... synchronizes version strings within the project 395 | > - [`git-changelog`](https://github.com/rivy-go/git-changelog) (v1.1+) ... enables changelog automation 396 | 397 | ### Quick build/test 398 | 399 | ```shell 400 | npm install-test 401 | ``` 402 | 403 | ### Contributions/development 404 | 405 | #### _Reproducible_ setup (for CI or local development) 406 | 407 | ```shell 408 | git clone "https://github.com/rivy/js.xdg-app-paths" 409 | cd js.xdg-app-paths 410 | # * note: for WinOS, replace `cp` with `copy` (or use [uutils](https://github.com/uutils/coreutils)) 411 | # npm 412 | cp .deps-lock/package-lock.json . 413 | npm clean-install 414 | # yarn 415 | cp .deps-lock/yarn.lock . 416 | yarn --immutable --immutable-cache --check-cache 417 | ``` 418 | 419 | #### Project development scripts 420 | 421 | ```shell 422 | > npm run help 423 | ... 424 | usage: `npm run TARGET` or `npx run-s TARGET [TARGET..]` 425 | 426 | TARGETs: 427 | 428 | build build/compile package 429 | clean remove build artifacts 430 | coverage calculate and display (or send) code coverage [alias: 'cov'] 431 | fix fix package issues (automated/non-interactive) 432 | fix:lint fix ESLint issues 433 | fix:style fix Prettier formatting issues 434 | help display help 435 | lint check for package code 'lint' 436 | lint:audit check for `npm audit` violations in project code 437 | lint:commits check for commit flaws (using `commitlint` and `cspell`) 438 | lint:editorconfig check for EditorConfig format flaws (using `editorconfig-checker`) 439 | lint:lint check for code 'lint' (using `eslint`) 440 | lint:markdown check for markdown errors (using `remark`) 441 | lint:spell check for spelling errors (using `cspell`) 442 | lint:style check for format imperfections (using `prettier`) 443 | prerelease clean, rebuild, and fully test (useful prior to publish/release) 444 | realclean remove all generated files 445 | rebuild clean and (re-)build project 446 | refresh clean and rebuild/regenerate all project artifacts 447 | refresh:dist clean, rebuild, and regenerate project distribution 448 | retest clean and (re-)test project 449 | reset:hard remove *all* generated files and reinstall dependencies 450 | show:deps show package dependencies 451 | test test package 452 | test:code test package code (use `--test-code=...` to pass options to testing harness) 453 | test:types test for type declaration errors (using `tsd`) 454 | update update/prepare for distribution [alias: 'dist'] 455 | update:changelog update CHANGELOG (using `git changelog ...`) 456 | update:dist update distribution content 457 | verify fully (and verbosely) test package 458 | ``` 459 | 460 | #### Packaging & Publishing 461 | 462 | ##### Package 463 | 464 | ```shell 465 | #=== * POSIX 466 | # update project VERSION strings (package.json,...) 467 | # * `bmp --[major|minor|patch]`; next VERSION in M.m.r (semver) format 468 | bmp --minor 469 | VERSION=$(cat VERSION) 470 | git-changelog --next-tag "v${VERSION}" > CHANGELOG.mkd 471 | # create/commit updates and distribution 472 | git add package.json CHANGELOG.mkd README.md VERSION .bmp.yml 473 | git commit -m "${VERSION}" 474 | npm run clean && npm run update:dist && git add dist && git commit --amend --no-edit 475 | # (optional) update/save dependency locks 476 | # * note: `yarn import` of 'package-lock.json' (when available) is faster but may not work for later versions of 'package-lock.json' 477 | rm -f package-lock.json yarn.lock 478 | npm install --package-lock 479 | yarn install 480 | mkdir .deps-lock 2> /dev/null 481 | cp package-lock.json .deps-lock/ 482 | cp yarn.lock .deps-lock/ 483 | git add .deps-lock 484 | git commit --amend --no-edit 485 | # tag VERSION commit 486 | git tag -f "v${VERSION}" 487 | # (optional) prerelease checkup 488 | npm run prerelease 489 | #=== * WinOS 490 | @rem # update project VERSION strings (package.json,...) 491 | @rem # * `bmp --[major|minor|patch]`; next VERSION in M.m.r (semver) format 492 | bmp --minor 493 | for /f %G in (VERSION) do @set "VERSION=%G" 494 | git-changelog --next-tag "v%VERSION%" > CHANGELOG.mkd 495 | @rem # create/commit updates and distribution 496 | git add package.json CHANGELOG.mkd README.md VERSION .bmp.yml 497 | git commit -m "%VERSION%" 498 | npm run clean && npm run update:dist && git add dist && git commit --amend --no-edit 499 | @rem # (optional) update/save dependency locks 500 | @rem # * note: `yarn import` of 'package-lock.json' (when available) is faster but may not work for later versions of 'package-lock.json' 501 | del package-lock.json yarn.lock 2>NUL 502 | npm install --package-lock 503 | yarn install 504 | mkdir .deps-lock 2>NUL 505 | copy /y package-lock.json .deps-lock >NUL 506 | copy /y yarn.lock .deps-lock >NUL 507 | git add .deps-lock 508 | git commit --amend --no-edit 509 | @rem # tag VERSION commit 510 | git tag -f "v%VERSION%" 511 | @rem # (optional) prerelease checkup 512 | npm run prerelease 513 | ``` 514 | 515 | ##### Publish 516 | 517 | ```shell 518 | # publish 519 | # * optional (will be done in 'prePublishOnly' by `npm publish`) 520 | npm run clean && npm run test && npm run dist && git-changelog > CHANGELOG.mkd #expect exit code == 0 521 | git diff-index --quiet HEAD || echo "[lint] ERROR uncommitted changes" # expect no output and exit code == 0 522 | # * 523 | npm publish # `npm publish --dry-run` will perform all prepublication actions and stop just before the actual publish push 524 | # * if published to NPMjs with no ERRORs; push to deno.land with tag push 525 | git push origin --tags 526 | ``` 527 | 528 | ### Contributions 529 | 530 | Contributions are welcome. 531 | 532 | Any pull requests should be based off of the default branch (`master`). And, whenever possible, please include tests for any new code, ensuring that local (via `npm test`) and remote CI testing passes. 533 | 534 | By contributing to the project, you are agreeing to provide your contributions under the same [license](./LICENSE) as the project itself. 535 | 536 | ## Related 537 | 538 | - [`xdg-portable`](https://www.npmjs.com/package/xdg-portable) ... XDG Base Directory paths (cross-platform) 539 | - [`env-paths`](https://www.npmjs.com/package/env-paths) ... inspiration for this module 540 | 541 | ## License 542 | 543 | [MIT](./LICENSE) © [Roy Ivy III](https://github.com/rivy) 544 | 545 | 546 | 547 | 548 | 549 | 550 | [repository-image]: https://img.shields.io/github/v/tag/rivy/js.xdg-app-paths?sort=semver&label=%E2%81%A3&logo=github&logoColor=white 551 | [repository-url]: https://github.com/rivy/js.xdg-app-paths 552 | [license-image]: https://img.shields.io/npm/l/xdg-app-paths.svg?color=tomato&style=flat 553 | [license-url]: license 554 | [nodejsv-image]: https://img.shields.io/node/v/xdg-app-paths?color=slateblue 555 | [style-image]: https://img.shields.io/badge/code_style-prettier-mediumvioletred.svg 556 | [style-url]: https://prettier.io 557 | 558 | 559 | 560 | [appveyor-image]: https://img.shields.io/appveyor/ci/rivy/js-xdg-app-paths/master.svg?style=flat&logo=AppVeyor&logoColor=deepskyblue 561 | [appveyor-url]: https://ci.appveyor.com/project/rivy/js-xdg-app-paths 562 | [gha-image]: https://img.shields.io/github/actions/workflow/status/rivy/js.xdg-app-paths/CI.yml?branch=master&label=CI&logo=github 563 | [gha-url]: https://github.com/rivy/js.xdg-app-paths/actions?query=workflow%3ACI 564 | 565 | 566 | 567 | [coverage-image]: https://img.shields.io/codecov/c/github/rivy/js.xdg-app-paths/master.svg 568 | [coverage-url]: https://codecov.io/gh/rivy/js.xdg-app-paths 569 | [codeclimate-url]: https://codeclimate.com/github/rivy/js.xdg-app-paths 570 | [codeclimate-image]: https://img.shields.io/codeclimate/maintainability/rivy/js.xdg-app-paths?label=codeclimate 571 | [codacy-image]: https://img.shields.io/codacy/grade/6f019c41b12b4c35a5ac5693744e4b96?label=codacy 572 | [codacy-url]: https://app.codacy.com/gh/rivy/js.xdg-app-paths/dashboard 573 | [codefactor-image]: https://img.shields.io/codefactor/grade/github/rivy/js.xdg-app-paths?label=codefactor 574 | [codefactor-url]: https://www.codefactor.io/repository/github/rivy/js.xdg-app-paths 575 | 576 | 577 | 578 | [deno-image]: https://img.shields.io/github/v/tag/rivy/js.xdg-app-paths?label=deno 579 | [deno-url]: https://deno.land/x/xdg_app_paths 580 | [downloads-image]: http://img.shields.io/npm/dm/xdg-app-paths.svg?style=flat 581 | [downloads-url]: https://npmjs.org/package/xdg-app-paths 582 | [jsdelivr-image]: https://img.shields.io/jsdelivr/gh/hm/rivy/js.xdg-app-paths?style=flat 583 | [jsdelivr-url]: https://www.jsdelivr.com/package/gh/rivy/js.xdg-app-paths 584 | [npm-image]: https://img.shields.io/npm/v/xdg-app-paths.svg?style=flat 585 | [npm-url]: https://npmjs.org/package/xdg-app-paths 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 8.3.0 2 | -------------------------------------------------------------------------------- /cjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "commonjs", 3 | "main": "../dist/cjs/mod.cjs.js", 4 | "types": "../dist/cjs/mod.cjs.d.ts" 5 | } 6 | -------------------------------------------------------------------------------- /dist/cjs/esm-wrapper/mod.esm.js: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | 3 | import _ from '../mod.cjs.js'; 4 | export * from '../mod.cjs.js'; 5 | export default _; 6 | -------------------------------------------------------------------------------- /dist/cjs/esm-wrapper/package.json: -------------------------------------------------------------------------------- 1 | {"type": "module"} 2 | -------------------------------------------------------------------------------- /dist/cjs/lib/XDGAppPaths.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | exports.__esModule = true; 3 | exports.Adapt = void 0; 4 | function isBoolean(t) { 5 | return typeOf(t) === 'boolean'; 6 | } 7 | function isObject(t) { 8 | return typeOf(t) === 'object'; 9 | } 10 | function isString(t) { 11 | return typeOf(t) === 'string'; 12 | } 13 | function typeOf(t) { 14 | return typeof t; 15 | } 16 | function Adapt(adapter_) { 17 | var meta = adapter_.meta, path = adapter_.path, xdg = adapter_.xdg; 18 | var XDGAppPaths_ = (function () { 19 | function XDGAppPaths_(options_) { 20 | if (options_ === void 0) { options_ = {}; } 21 | var _a, _b, _c; 22 | function XDGAppPaths(options) { 23 | if (options === void 0) { options = {}; } 24 | return new XDGAppPaths_(options); 25 | } 26 | var options = (isObject(options_) ? options_ : { name: options_ }); 27 | var suffix = (_a = options.suffix) !== null && _a !== void 0 ? _a : ''; 28 | var isolated_ = (_b = options.isolated) !== null && _b !== void 0 ? _b : true; 29 | var namePriorityList = [ 30 | options.name, 31 | meta.pkgMainFilename(), 32 | meta.mainFilename(), 33 | ]; 34 | var nameFallback = '$eval'; 35 | var name = path.parse(((_c = namePriorityList.find(function (e) { return isString(e); })) !== null && _c !== void 0 ? _c : nameFallback) + suffix).name; 36 | XDGAppPaths.$name = function $name() { 37 | return name; 38 | }; 39 | XDGAppPaths.$isolated = function $isolated() { 40 | return isolated_; 41 | }; 42 | function isIsolated(dirOptions) { 43 | var _a; 44 | dirOptions = dirOptions !== null && dirOptions !== void 0 ? dirOptions : { isolated: isolated_ }; 45 | var isolated = isBoolean(dirOptions) ? dirOptions : (_a = dirOptions.isolated) !== null && _a !== void 0 ? _a : isolated_; 46 | return isolated; 47 | } 48 | function finalPathSegment(dirOptions) { 49 | return isIsolated(dirOptions) ? name : ''; 50 | } 51 | XDGAppPaths.cache = function cache(dirOptions) { 52 | return path.join(xdg.cache(), finalPathSegment(dirOptions)); 53 | }; 54 | XDGAppPaths.config = function config(dirOptions) { 55 | return path.join(xdg.config(), finalPathSegment(dirOptions)); 56 | }; 57 | XDGAppPaths.data = function data(dirOptions) { 58 | return path.join(xdg.data(), finalPathSegment(dirOptions)); 59 | }; 60 | XDGAppPaths.runtime = function runtime(dirOptions) { 61 | return xdg.runtime() 62 | ? path.join(xdg.runtime(), finalPathSegment(dirOptions)) 63 | : void 0; 64 | }; 65 | XDGAppPaths.state = function state(dirOptions) { 66 | return path.join(xdg.state(), finalPathSegment(dirOptions)); 67 | }; 68 | XDGAppPaths.configDirs = function configDirs(dirOptions) { 69 | return xdg 70 | .configDirs() 71 | .map(function (s) { return path.join(s, finalPathSegment(dirOptions)); }); 72 | }; 73 | XDGAppPaths.dataDirs = function dataDirs(dirOptions) { 74 | return xdg 75 | .dataDirs() 76 | .map(function (s) { return path.join(s, finalPathSegment(dirOptions)); }); 77 | }; 78 | return XDGAppPaths; 79 | } 80 | return XDGAppPaths_; 81 | }()); 82 | return { XDGAppPaths: new XDGAppPaths_() }; 83 | } 84 | exports.Adapt = Adapt; 85 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiWERHQXBwUGF0aHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL1hER0FwcFBhdGhzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLFlBQVksQ0FBQzs7O0FBbUZiLFNBQVMsU0FBUyxDQUFJLENBQWM7SUFDbkMsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssU0FBUyxDQUFDO0FBQ2hDLENBQUM7QUFFRCxTQUFTLFFBQVEsQ0FBSSxDQUE4QjtJQUNsRCxPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLENBQUM7QUFDL0IsQ0FBQztBQUVELFNBQVMsUUFBUSxDQUFJLENBQUk7SUFDeEIsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUSxDQUFDO0FBQy9CLENBQUM7QUFFRCxTQUFTLE1BQU0sQ0FBSSxDQUFJO0lBQ3RCLE9BQU8sT0FBTyxDQUFDLENBQUM7QUFDakIsQ0FBQztBQUVELFNBQVMsS0FBSyxDQUFDLFFBQTBCO0lBQ2hDLElBQUEsSUFBSSxHQUFnQixRQUFRLEtBQXhCLEVBQUUsSUFBSSxHQUFVLFFBQVEsS0FBbEIsRUFBRSxHQUFHLEdBQUssUUFBUSxJQUFiLENBQWM7SUFFckM7UUFDQyxzQkFBWSxRQUErQjtZQUEvQix5QkFBQSxFQUFBLGFBQStCOztZQUMxQyxTQUFTLFdBQVcsQ0FBQyxPQUE4QjtnQkFBOUIsd0JBQUEsRUFBQSxZQUE4QjtnQkFDbEQsT0FBTyxJQUFJLFlBQVksQ0FBQyxPQUFPLENBQWdCLENBQUM7WUFDakQsQ0FBQztZQUVELElBQU0sT0FBTyxHQUFHLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFZLENBQUM7WUFFaEYsSUFBTSxNQUFNLEdBQUcsTUFBQSxPQUFPLENBQUMsTUFBTSxtQ0FBSSxFQUFFLENBQUM7WUFDcEMsSUFBTSxTQUFTLEdBQUcsTUFBQSxPQUFPLENBQUMsUUFBUSxtQ0FBSSxJQUFJLENBQUM7WUFHM0MsSUFBTSxnQkFBZ0IsR0FBNkM7Z0JBQ2xFLE9BQU8sQ0FBQyxJQUFJO2dCQUNaLElBQUksQ0FBQyxlQUFlLEVBQUU7Z0JBQ3RCLElBQUksQ0FBQyxZQUFZLEVBQUU7YUFDbkIsQ0FBQztZQUNGLElBQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQztZQUM3QixJQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUN0QixDQUFDLE1BQUEsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLFVBQUMsQ0FBQyxJQUFLLE9BQUEsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFYLENBQVcsQ0FBQyxtQ0FBSSxZQUFZLENBQUMsR0FBRyxNQUFNLENBQ3BFLENBQUMsSUFBSSxDQUFDO1lBRVAsV0FBVyxDQUFDLEtBQUssR0FBRyxTQUFTLEtBQUs7Z0JBQ2pDLE9BQU8sSUFBSSxDQUFDO1lBQ2IsQ0FBQyxDQUFDO1lBQ0YsV0FBVyxDQUFDLFNBQVMsR0FBRyxTQUFTLFNBQVM7Z0JBQ3pDLE9BQU8sU0FBUyxDQUFDO1lBQ2xCLENBQUMsQ0FBQztZQUVGLFNBQVMsVUFBVSxDQUFDLFVBQWlDOztnQkFDcEQsVUFBVSxHQUFHLFVBQVUsYUFBVixVQUFVLGNBQVYsVUFBVSxHQUFJLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxDQUFDO2dCQUNuRCxJQUFNLFFBQVEsR0FBRyxTQUFTLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsTUFBQSxVQUFVLENBQUMsUUFBUSxtQ0FBSSxTQUFTLENBQUM7Z0JBQ3ZGLE9BQU8sUUFBUSxDQUFDO1lBQ2pCLENBQUM7WUFFRCxTQUFTLGdCQUFnQixDQUFDLFVBQWlDO2dCQUMxRCxPQUFPLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDM0MsQ0FBQztZQUVELFdBQVcsQ0FBQyxLQUFLLEdBQUcsU0FBUyxLQUFLLENBQUMsVUFBaUM7Z0JBQ25FLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsZ0JBQWdCLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztZQUM3RCxDQUFDLENBQUM7WUFFRixXQUFXLENBQUMsTUFBTSxHQUFHLFNBQVMsTUFBTSxDQUFDLFVBQWlDO2dCQUNyRSxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxFQUFFLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7WUFDOUQsQ0FBQyxDQUFDO1lBRUYsV0FBVyxDQUFDLElBQUksR0FBRyxTQUFTLElBQUksQ0FBQyxVQUFpQztnQkFDakUsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsRUFBRSxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1lBQzVELENBQUMsQ0FBQztZQUVGLFdBQVcsQ0FBQyxPQUFPLEdBQUcsU0FBUyxPQUFPLENBQUMsVUFBaUM7Z0JBQ3ZFLE9BQU8sR0FBRyxDQUFDLE9BQU8sRUFBRTtvQkFDbkIsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBWSxFQUFFLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxDQUFDO29CQUNsRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDWCxDQUFDLENBQUM7WUFFRixXQUFXLENBQUMsS0FBSyxHQUFHLFNBQVMsS0FBSyxDQUFDLFVBQWlDO2dCQUNuRSxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7WUFDN0QsQ0FBQyxDQUFDO1lBRUYsV0FBVyxDQUFDLFVBQVUsR0FBRyxTQUFTLFVBQVUsQ0FBQyxVQUFpQztnQkFDN0UsT0FBTyxHQUFHO3FCQUNSLFVBQVUsRUFBRTtxQkFDWixHQUFHLENBQUMsVUFBQyxDQUFDLElBQUssT0FBQSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsQ0FBQyxFQUExQyxDQUEwQyxDQUFzQixDQUFDO1lBQy9FLENBQUMsQ0FBQztZQUVGLFdBQVcsQ0FBQyxRQUFRLEdBQUcsU0FBUyxRQUFRLENBQUMsVUFBaUM7Z0JBQ3pFLE9BQU8sR0FBRztxQkFDUixRQUFRLEVBQUU7cUJBQ1YsR0FBRyxDQUFDLFVBQUMsQ0FBQyxJQUFLLE9BQUEsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsZ0JBQWdCLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBMUMsQ0FBMEMsQ0FBc0IsQ0FBQztZQUMvRSxDQUFDLENBQUM7WUFFRixPQUFPLFdBQTBCLENBQUM7UUFDbkMsQ0FBQztRQUNGLG1CQUFDO0lBQUQsQ0FBQyxBQTNFRCxJQTJFQztJQUVELE9BQU8sRUFBRSxXQUFXLEVBQUUsSUFBSSxZQUFZLEVBQWlCLEVBQUUsQ0FBQztBQUMzRCxDQUFDO0FBR1Esc0JBQUsifQ== -------------------------------------------------------------------------------- /dist/cjs/mod.cjs.d.ts: -------------------------------------------------------------------------------- 1 | /** Configuration options supplied to `XDGAppPaths` methods */ 2 | interface DirOptions { 3 | /** Isolation flag; used to override the default isolation mode, when needed. */ 4 | readonly isolated?: boolean | null; 5 | } 6 | /** Configuration options supplied when constructing `XDGAppPaths` */ 7 | interface Options { 8 | /** Name of the application; used to generate isolated application paths. 9 | > When missing (`undefined`), `null`, or empty (`''`), it is generated automatically from the process main file name, where determinable. 10 | > "$eval" is used as a final fallback value when the application name cannot otherwise be determined. 11 | */ 12 | readonly name?: string | null; 13 | /** Suffix which is appended to the application name when generating the application paths. */ 14 | readonly suffix?: string | null; 15 | /** Default isolation flag (used when no isolation flag is supplied for `DirOptions`). */ 16 | readonly isolated?: boolean | null; 17 | } 18 | /** `XDGAppPaths` (API) - Determine (XDG-compatible) paths for storing application files (cache, config, data, etc) */ 19 | interface XDGAppPaths { 20 | /** Create an `XDGAppPaths` object (a preceding `new` is optional). */ 21 | (options?: Options | string): XDGAppPaths; 22 | /** Create an `XDGAppPaths` object (`new` is optional). */ 23 | new (options?: Options | string): XDGAppPaths; 24 | /** Returns the directory for non-essential data files. 25 | > Deletion of the data contained here might cause an application to slow down. 26 | */ 27 | cache(dirOptions?: DirOptions | boolean): string; 28 | /** Returns the directory for config files. 29 | > Deletion of the data contained here might require the user to reconfigure an application. 30 | */ 31 | config(dirOptions?: DirOptions | boolean): string; 32 | /** Returns the directory for data files. 33 | > Deletion of the data contained here might force the user to restore from backups. 34 | */ 35 | data(dirOptions?: DirOptions | boolean): string; 36 | /** Returns the directory for runtime files; may return `undefined`. 37 | > Deletion of the data contained here might interfere with a currently executing application but should have no effect on future executions. 38 | */ 39 | runtime(dirOptions?: DirOptions | boolean): string | undefined; 40 | /** Returns the directory for state files. 41 | > Deletion of the data contained here should not materially interfere with execution of an application. 42 | */ 43 | state(dirOptions?: DirOptions | boolean): string; 44 | /** Returns a priority-sorted list of possible directories for configuration file storage (includes `paths.config()` as the first entry). */ 45 | configDirs(dirOptions?: DirOptions | boolean): readonly string[]; 46 | /** Returns a priority-sorted list of possible directories for data file storage (includes `paths.data()` as the first entry). */ 47 | dataDirs(dirOptions?: DirOptions | boolean): readonly string[]; 48 | /** Application name used for path construction (from supplied configuration or auto-generated). */ 49 | $name(): string; 50 | /** Default isolation mode used by the particular `XDGAppPaths` instance. */ 51 | $isolated(): boolean; 52 | } 53 | 54 | declare const _default: XDGAppPaths; 55 | 56 | export = _default; 57 | -------------------------------------------------------------------------------- /dist/cjs/mod.cjs.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var XDGAppPaths_js_1 = require("./lib/XDGAppPaths.js"); 3 | var node_js_1 = require("./platform-adapters/node.js"); 4 | module.exports = XDGAppPaths_js_1.Adapt(node_js_1.adapter).XDGAppPaths; 5 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kLmNqcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tb2QuY2pzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFFQSx1REFBNkM7QUFFN0MsdURBQXNEO0FBRXRELGlCQUFTLHNCQUFLLENBQUMsaUJBQU8sQ0FBQyxDQUFDLFdBQTBCLENBQUMifQ== -------------------------------------------------------------------------------- /dist/cjs/platform-adapters/_base.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2Jhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvcGxhdGZvcm0tYWRhcHRlcnMvX2Jhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9 -------------------------------------------------------------------------------- /dist/cjs/platform-adapters/node.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 5 | }) : (function(o, m, k, k2) { 6 | if (k2 === undefined) k2 = k; 7 | o[k2] = m[k]; 8 | })); 9 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 10 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 11 | }) : function(o, v) { 12 | o["default"] = v; 13 | }); 14 | var __importStar = (this && this.__importStar) || function (mod) { 15 | if (mod && mod.__esModule) return mod; 16 | var result = {}; 17 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 18 | __setModuleDefault(result, mod); 19 | return result; 20 | }; 21 | var __importDefault = (this && this.__importDefault) || function (mod) { 22 | return (mod && mod.__esModule) ? mod : { "default": mod }; 23 | }; 24 | exports.__esModule = true; 25 | exports.adapter = void 0; 26 | var path = __importStar(require("path")); 27 | var xdg_portable_1 = __importDefault(require("xdg-portable")); 28 | exports.adapter = { 29 | atImportPermissions: { env: true, read: true }, 30 | meta: { 31 | mainFilename: function () { 32 | var requireMain = typeof require !== 'undefined' && require !== null && require.main 33 | ? require.main 34 | : { filename: void 0 }; 35 | var requireMainFilename = requireMain.filename; 36 | var filename = (requireMainFilename !== process.execArgv[0] ? requireMainFilename : void 0) || 37 | (typeof process._eval === 'undefined' ? process.argv[1] : void 0); 38 | return filename; 39 | }, 40 | pkgMainFilename: function () { 41 | return process.pkg ? process.execPath : void 0; 42 | } 43 | }, 44 | path: path, 45 | process: process, 46 | xdg: xdg_portable_1["default"] 47 | }; 48 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9wbGF0Zm9ybS1hZGFwdGVycy9ub2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFQSx5Q0FBNkI7QUFFN0IsOERBQStCO0FBSWxCLFFBQUEsT0FBTyxHQUFxQjtJQUN4QyxtQkFBbUIsRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRTtJQUM5QyxJQUFJLEVBQUU7UUFDTCxZQUFZLEVBQUU7WUFDYixJQUFNLFdBQVcsR0FDaEIsT0FBTyxPQUFPLEtBQUssV0FBVyxJQUFJLE9BQU8sS0FBSyxJQUFJLElBQUksT0FBTyxDQUFDLElBQUk7Z0JBQ2pFLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSTtnQkFDZCxDQUFDLENBQUMsRUFBRSxRQUFRLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN6QixJQUFNLG1CQUFtQixHQUFHLFdBQVcsQ0FBQyxRQUFRLENBQUM7WUFDakQsSUFBTSxRQUFRLEdBRWIsQ0FBQyxtQkFBbUIsS0FBSyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBRzVFLENBQUMsT0FBUSxPQUFlLENBQUMsS0FBSyxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztZQUM1RSxPQUFPLFFBQVEsQ0FBQztRQUNqQixDQUFDO1FBQ0QsZUFBZSxFQUFFO1lBRWhCLE9BQVEsT0FBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDekQsQ0FBQztLQUNEO0lBQ0QsSUFBSSxNQUFBO0lBQ0osT0FBTyxTQUFBO0lBQ1AsR0FBRywyQkFBQTtDQUNILENBQUMifQ== -------------------------------------------------------------------------------- /dist/esm/lib/XDGAppPaths.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | function isBoolean(t) { 3 | return typeOf(t) === 'boolean'; 4 | } 5 | function isObject(t) { 6 | return typeOf(t) === 'object'; 7 | } 8 | function isString(t) { 9 | return typeOf(t) === 'string'; 10 | } 11 | function typeOf(t) { 12 | return typeof t; 13 | } 14 | function Adapt(adapter_) { 15 | var meta = adapter_.meta, path = adapter_.path, xdg = adapter_.xdg; 16 | var XDGAppPaths_ = (function () { 17 | function XDGAppPaths_(options_) { 18 | if (options_ === void 0) { options_ = {}; } 19 | var _a, _b, _c; 20 | function XDGAppPaths(options) { 21 | if (options === void 0) { options = {}; } 22 | return new XDGAppPaths_(options); 23 | } 24 | var options = (isObject(options_) ? options_ : { name: options_ }); 25 | var suffix = (_a = options.suffix) !== null && _a !== void 0 ? _a : ''; 26 | var isolated_ = (_b = options.isolated) !== null && _b !== void 0 ? _b : true; 27 | var namePriorityList = [ 28 | options.name, 29 | meta.pkgMainFilename(), 30 | meta.mainFilename(), 31 | ]; 32 | var nameFallback = '$eval'; 33 | var name = path.parse(((_c = namePriorityList.find(function (e) { return isString(e); })) !== null && _c !== void 0 ? _c : nameFallback) + suffix).name; 34 | XDGAppPaths.$name = function $name() { 35 | return name; 36 | }; 37 | XDGAppPaths.$isolated = function $isolated() { 38 | return isolated_; 39 | }; 40 | function isIsolated(dirOptions) { 41 | var _a; 42 | dirOptions = dirOptions !== null && dirOptions !== void 0 ? dirOptions : { isolated: isolated_ }; 43 | var isolated = isBoolean(dirOptions) ? dirOptions : (_a = dirOptions.isolated) !== null && _a !== void 0 ? _a : isolated_; 44 | return isolated; 45 | } 46 | function finalPathSegment(dirOptions) { 47 | return isIsolated(dirOptions) ? name : ''; 48 | } 49 | XDGAppPaths.cache = function cache(dirOptions) { 50 | return path.join(xdg.cache(), finalPathSegment(dirOptions)); 51 | }; 52 | XDGAppPaths.config = function config(dirOptions) { 53 | return path.join(xdg.config(), finalPathSegment(dirOptions)); 54 | }; 55 | XDGAppPaths.data = function data(dirOptions) { 56 | return path.join(xdg.data(), finalPathSegment(dirOptions)); 57 | }; 58 | XDGAppPaths.runtime = function runtime(dirOptions) { 59 | return xdg.runtime() 60 | ? path.join(xdg.runtime(), finalPathSegment(dirOptions)) 61 | : void 0; 62 | }; 63 | XDGAppPaths.state = function state(dirOptions) { 64 | return path.join(xdg.state(), finalPathSegment(dirOptions)); 65 | }; 66 | XDGAppPaths.configDirs = function configDirs(dirOptions) { 67 | return xdg 68 | .configDirs() 69 | .map(function (s) { return path.join(s, finalPathSegment(dirOptions)); }); 70 | }; 71 | XDGAppPaths.dataDirs = function dataDirs(dirOptions) { 72 | return xdg 73 | .dataDirs() 74 | .map(function (s) { return path.join(s, finalPathSegment(dirOptions)); }); 75 | }; 76 | return XDGAppPaths; 77 | } 78 | return XDGAppPaths_; 79 | }()); 80 | return { XDGAppPaths: new XDGAppPaths_() }; 81 | } 82 | export { Adapt }; 83 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiWERHQXBwUGF0aHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL1hER0FwcFBhdGhzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLFlBQVksQ0FBQztBQW1GYixTQUFTLFNBQVMsQ0FBSSxDQUFjO0lBQ25DLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLFNBQVMsQ0FBQztBQUNoQyxDQUFDO0FBRUQsU0FBUyxRQUFRLENBQUksQ0FBOEI7SUFDbEQsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUSxDQUFDO0FBQy9CLENBQUM7QUFFRCxTQUFTLFFBQVEsQ0FBSSxDQUFJO0lBQ3hCLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVEsQ0FBQztBQUMvQixDQUFDO0FBRUQsU0FBUyxNQUFNLENBQUksQ0FBSTtJQUN0QixPQUFPLE9BQU8sQ0FBQyxDQUFDO0FBQ2pCLENBQUM7QUFFRCxTQUFTLEtBQUssQ0FBQyxRQUEwQjtJQUNoQyxJQUFBLElBQUksR0FBZ0IsUUFBUSxLQUF4QixFQUFFLElBQUksR0FBVSxRQUFRLEtBQWxCLEVBQUUsR0FBRyxHQUFLLFFBQVEsSUFBYixDQUFjO0lBRXJDO1FBQ0Msc0JBQVksUUFBK0I7WUFBL0IseUJBQUEsRUFBQSxhQUErQjs7WUFDMUMsU0FBUyxXQUFXLENBQUMsT0FBOEI7Z0JBQTlCLHdCQUFBLEVBQUEsWUFBOEI7Z0JBQ2xELE9BQU8sSUFBSSxZQUFZLENBQUMsT0FBTyxDQUFnQixDQUFDO1lBQ2pELENBQUM7WUFFRCxJQUFNLE9BQU8sR0FBRyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBWSxDQUFDO1lBRWhGLElBQU0sTUFBTSxHQUFHLE1BQUEsT0FBTyxDQUFDLE1BQU0sbUNBQUksRUFBRSxDQUFDO1lBQ3BDLElBQU0sU0FBUyxHQUFHLE1BQUEsT0FBTyxDQUFDLFFBQVEsbUNBQUksSUFBSSxDQUFDO1lBRzNDLElBQU0sZ0JBQWdCLEdBQTZDO2dCQUNsRSxPQUFPLENBQUMsSUFBSTtnQkFDWixJQUFJLENBQUMsZUFBZSxFQUFFO2dCQUN0QixJQUFJLENBQUMsWUFBWSxFQUFFO2FBQ25CLENBQUM7WUFDRixJQUFNLFlBQVksR0FBRyxPQUFPLENBQUM7WUFDN0IsSUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FDdEIsQ0FBQyxNQUFBLGdCQUFnQixDQUFDLElBQUksQ0FBQyxVQUFDLENBQUMsSUFBSyxPQUFBLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBWCxDQUFXLENBQUMsbUNBQUksWUFBWSxDQUFDLEdBQUcsTUFBTSxDQUNwRSxDQUFDLElBQUksQ0FBQztZQUVQLFdBQVcsQ0FBQyxLQUFLLEdBQUcsU0FBUyxLQUFLO2dCQUNqQyxPQUFPLElBQUksQ0FBQztZQUNiLENBQUMsQ0FBQztZQUNGLFdBQVcsQ0FBQyxTQUFTLEdBQUcsU0FBUyxTQUFTO2dCQUN6QyxPQUFPLFNBQVMsQ0FBQztZQUNsQixDQUFDLENBQUM7WUFFRixTQUFTLFVBQVUsQ0FBQyxVQUFpQzs7Z0JBQ3BELFVBQVUsR0FBRyxVQUFVLGFBQVYsVUFBVSxjQUFWLFVBQVUsR0FBSSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsQ0FBQztnQkFDbkQsSUFBTSxRQUFRLEdBQUcsU0FBUyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLE1BQUEsVUFBVSxDQUFDLFFBQVEsbUNBQUksU0FBUyxDQUFDO2dCQUN2RixPQUFPLFFBQVEsQ0FBQztZQUNqQixDQUFDO1lBRUQsU0FBUyxnQkFBZ0IsQ0FBQyxVQUFpQztnQkFDMUQsT0FBTyxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQzNDLENBQUM7WUFFRCxXQUFXLENBQUMsS0FBSyxHQUFHLFNBQVMsS0FBSyxDQUFDLFVBQWlDO2dCQUNuRSxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7WUFDN0QsQ0FBQyxDQUFDO1lBRUYsV0FBVyxDQUFDLE1BQU0sR0FBRyxTQUFTLE1BQU0sQ0FBQyxVQUFpQztnQkFDckUsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsRUFBRSxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1lBQzlELENBQUMsQ0FBQztZQUVGLFdBQVcsQ0FBQyxJQUFJLEdBQUcsU0FBUyxJQUFJLENBQUMsVUFBaUM7Z0JBQ2pFLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsZ0JBQWdCLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztZQUM1RCxDQUFDLENBQUM7WUFFRixXQUFXLENBQUMsT0FBTyxHQUFHLFNBQVMsT0FBTyxDQUFDLFVBQWlDO2dCQUN2RSxPQUFPLEdBQUcsQ0FBQyxPQUFPLEVBQUU7b0JBQ25CLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQVksRUFBRSxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztvQkFDbEUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ1gsQ0FBQyxDQUFDO1lBRUYsV0FBVyxDQUFDLEtBQUssR0FBRyxTQUFTLEtBQUssQ0FBQyxVQUFpQztnQkFDbkUsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRSxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1lBQzdELENBQUMsQ0FBQztZQUVGLFdBQVcsQ0FBQyxVQUFVLEdBQUcsU0FBUyxVQUFVLENBQUMsVUFBaUM7Z0JBQzdFLE9BQU8sR0FBRztxQkFDUixVQUFVLEVBQUU7cUJBQ1osR0FBRyxDQUFDLFVBQUMsQ0FBQyxJQUFLLE9BQUEsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsZ0JBQWdCLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBMUMsQ0FBMEMsQ0FBc0IsQ0FBQztZQUMvRSxDQUFDLENBQUM7WUFFRixXQUFXLENBQUMsUUFBUSxHQUFHLFNBQVMsUUFBUSxDQUFDLFVBQWlDO2dCQUN6RSxPQUFPLEdBQUc7cUJBQ1IsUUFBUSxFQUFFO3FCQUNWLEdBQUcsQ0FBQyxVQUFDLENBQUMsSUFBSyxPQUFBLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQTFDLENBQTBDLENBQXNCLENBQUM7WUFDL0UsQ0FBQyxDQUFDO1lBRUYsT0FBTyxXQUEwQixDQUFDO1FBQ25DLENBQUM7UUFDRixtQkFBQztJQUFELENBQUMsQUEzRUQsSUEyRUM7SUFFRCxPQUFPLEVBQUUsV0FBVyxFQUFFLElBQUksWUFBWSxFQUFpQixFQUFFLENBQUM7QUFDM0QsQ0FBQztBQUdELE9BQU8sRUFBRSxLQUFLLEVBQUUsQ0FBQyJ9 -------------------------------------------------------------------------------- /dist/esm/mod.esm.js: -------------------------------------------------------------------------------- 1 | import { Adapt } from './lib/XDGAppPaths.js'; 2 | import { adapter } from './platform-adapters/node.js'; 3 | var _ = Adapt(adapter).XDGAppPaths; 4 | export default _; 5 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kLmVzbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tb2QuZXNtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUU3QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFdEQsSUFBTSxDQUFDLEdBQWdCLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUEwQixDQUFDO0FBR2pFLGVBQWUsQ0FBQyxDQUFDIn0= -------------------------------------------------------------------------------- /dist/esm/package.json: -------------------------------------------------------------------------------- 1 | {"type": "module"} 2 | -------------------------------------------------------------------------------- /dist/esm/platform-adapters/_base.js: -------------------------------------------------------------------------------- 1 | export {}; 2 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2Jhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvcGxhdGZvcm0tYWRhcHRlcnMvX2Jhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9 -------------------------------------------------------------------------------- /dist/esm/platform-adapters/node.js: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import xdg from 'xdg-portable'; 3 | export var adapter = { 4 | atImportPermissions: { env: true, read: true }, 5 | meta: { 6 | mainFilename: function () { 7 | var requireMain = typeof require !== 'undefined' && require !== null && require.main 8 | ? require.main 9 | : { filename: void 0 }; 10 | var requireMainFilename = requireMain.filename; 11 | var filename = (requireMainFilename !== process.execArgv[0] ? requireMainFilename : void 0) || 12 | (typeof process._eval === 'undefined' ? process.argv[1] : void 0); 13 | return filename; 14 | }, 15 | pkgMainFilename: function () { 16 | return process.pkg ? process.execPath : void 0; 17 | } 18 | }, 19 | path: path, 20 | process: process, 21 | xdg: xdg 22 | }; 23 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9wbGF0Zm9ybS1hZGFwdGVycy9ub2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBRTdCLE9BQU8sR0FBRyxNQUFNLGNBQWMsQ0FBQztBQUkvQixNQUFNLENBQUMsSUFBTSxPQUFPLEdBQXFCO0lBQ3hDLG1CQUFtQixFQUFFLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFO0lBQzlDLElBQUksRUFBRTtRQUNMLFlBQVksRUFBRTtZQUNiLElBQU0sV0FBVyxHQUNoQixPQUFPLE9BQU8sS0FBSyxXQUFXLElBQUksT0FBTyxLQUFLLElBQUksSUFBSSxPQUFPLENBQUMsSUFBSTtnQkFDakUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJO2dCQUNkLENBQUMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3pCLElBQU0sbUJBQW1CLEdBQUcsV0FBVyxDQUFDLFFBQVEsQ0FBQztZQUNqRCxJQUFNLFFBQVEsR0FFYixDQUFDLG1CQUFtQixLQUFLLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFHNUUsQ0FBQyxPQUFRLE9BQWUsQ0FBQyxLQUFLLEtBQUssV0FBVyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQzVFLE9BQU8sUUFBUSxDQUFDO1FBQ2pCLENBQUM7UUFDRCxlQUFlLEVBQUU7WUFFaEIsT0FBUSxPQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN6RCxDQUFDO0tBQ0Q7SUFDRCxJQUFJLE1BQUE7SUFDSixPQUFPLFNBQUE7SUFDUCxHQUFHLEtBQUE7Q0FDSCxDQUFDIn0= -------------------------------------------------------------------------------- /dist/types/mod.cjs.d.ts: -------------------------------------------------------------------------------- 1 | /** Configuration options supplied to `XDGAppPaths` methods */ 2 | interface DirOptions { 3 | /** Isolation flag; used to override the default isolation mode, when needed. */ 4 | readonly isolated?: boolean | null; 5 | } 6 | /** Configuration options supplied when constructing `XDGAppPaths` */ 7 | interface Options { 8 | /** Name of the application; used to generate isolated application paths. 9 | > When missing (`undefined`), `null`, or empty (`''`), it is generated automatically from the process main file name, where determinable. 10 | > "$eval" is used as a final fallback value when the application name cannot otherwise be determined. 11 | */ 12 | readonly name?: string | null; 13 | /** Suffix which is appended to the application name when generating the application paths. */ 14 | readonly suffix?: string | null; 15 | /** Default isolation flag (used when no isolation flag is supplied for `DirOptions`). */ 16 | readonly isolated?: boolean | null; 17 | } 18 | /** `XDGAppPaths` (API) - Determine (XDG-compatible) paths for storing application files (cache, config, data, etc) */ 19 | interface XDGAppPaths { 20 | /** Create an `XDGAppPaths` object (a preceding `new` is optional). */ 21 | (options?: Options | string): XDGAppPaths; 22 | /** Create an `XDGAppPaths` object (`new` is optional). */ 23 | new (options?: Options | string): XDGAppPaths; 24 | /** Returns the directory for non-essential data files. 25 | > Deletion of the data contained here might cause an application to slow down. 26 | */ 27 | cache(dirOptions?: DirOptions | boolean): string; 28 | /** Returns the directory for config files. 29 | > Deletion of the data contained here might require the user to reconfigure an application. 30 | */ 31 | config(dirOptions?: DirOptions | boolean): string; 32 | /** Returns the directory for data files. 33 | > Deletion of the data contained here might force the user to restore from backups. 34 | */ 35 | data(dirOptions?: DirOptions | boolean): string; 36 | /** Returns the directory for runtime files; may return `undefined`. 37 | > Deletion of the data contained here might interfere with a currently executing application but should have no effect on future executions. 38 | */ 39 | runtime(dirOptions?: DirOptions | boolean): string | undefined; 40 | /** Returns the directory for state files. 41 | > Deletion of the data contained here should not materially interfere with execution of an application. 42 | */ 43 | state(dirOptions?: DirOptions | boolean): string; 44 | /** Returns a priority-sorted list of possible directories for configuration file storage (includes `paths.config()` as the first entry). */ 45 | configDirs(dirOptions?: DirOptions | boolean): readonly string[]; 46 | /** Returns a priority-sorted list of possible directories for data file storage (includes `paths.data()` as the first entry). */ 47 | dataDirs(dirOptions?: DirOptions | boolean): readonly string[]; 48 | /** Application name used for path construction (from supplied configuration or auto-generated). */ 49 | $name(): string; 50 | /** Default isolation mode used by the particular `XDGAppPaths` instance. */ 51 | $isolated(): boolean; 52 | } 53 | 54 | declare const _default: XDGAppPaths; 55 | 56 | export = _default; 57 | -------------------------------------------------------------------------------- /dist/types/mod.d.ts: -------------------------------------------------------------------------------- 1 | /** Configuration options supplied to `XDGAppPaths` methods */ 2 | interface DirOptions { 3 | /** Isolation flag; used to override the default isolation mode, when needed. */ 4 | readonly isolated?: boolean | null; 5 | } 6 | /** Configuration options supplied when constructing `XDGAppPaths` */ 7 | interface Options { 8 | /** Name of the application; used to generate isolated application paths. 9 | > When missing (`undefined`), `null`, or empty (`''`), it is generated automatically from the process main file name, where determinable. 10 | > "$eval" is used as a final fallback value when the application name cannot otherwise be determined. 11 | */ 12 | readonly name?: string | null; 13 | /** Suffix which is appended to the application name when generating the application paths. */ 14 | readonly suffix?: string | null; 15 | /** Default isolation flag (used when no isolation flag is supplied for `DirOptions`). */ 16 | readonly isolated?: boolean | null; 17 | } 18 | /** `XDGAppPaths` (API) - Determine (XDG-compatible) paths for storing application files (cache, config, data, etc) */ 19 | interface XDGAppPaths { 20 | /** Create an `XDGAppPaths` object (a preceding `new` is optional). */ 21 | (options?: Options | string): XDGAppPaths; 22 | /** Create an `XDGAppPaths` object (`new` is optional). */ 23 | new (options?: Options | string): XDGAppPaths; 24 | /** Returns the directory for non-essential data files. 25 | > Deletion of the data contained here might cause an application to slow down. 26 | */ 27 | cache(dirOptions?: DirOptions | boolean): string; 28 | /** Returns the directory for config files. 29 | > Deletion of the data contained here might require the user to reconfigure an application. 30 | */ 31 | config(dirOptions?: DirOptions | boolean): string; 32 | /** Returns the directory for data files. 33 | > Deletion of the data contained here might force the user to restore from backups. 34 | */ 35 | data(dirOptions?: DirOptions | boolean): string; 36 | /** Returns the directory for runtime files; may return `undefined`. 37 | > Deletion of the data contained here might interfere with a currently executing application but should have no effect on future executions. 38 | */ 39 | runtime(dirOptions?: DirOptions | boolean): string | undefined; 40 | /** Returns the directory for state files. 41 | > Deletion of the data contained here should not materially interfere with execution of an application. 42 | */ 43 | state(dirOptions?: DirOptions | boolean): string; 44 | /** Returns a priority-sorted list of possible directories for configuration file storage (includes `paths.config()` as the first entry). */ 45 | configDirs(dirOptions?: DirOptions | boolean): readonly string[]; 46 | /** Returns a priority-sorted list of possible directories for data file storage (includes `paths.data()` as the first entry). */ 47 | dataDirs(dirOptions?: DirOptions | boolean): readonly string[]; 48 | /** Application name used for path construction (from supplied configuration or auto-generated). */ 49 | $name(): string; 50 | /** Default isolation mode used by the particular `XDGAppPaths` instance. */ 51 | $isolated(): boolean; 52 | } 53 | 54 | declare const _: XDGAppPaths; 55 | 56 | export { DirOptions, Options, XDGAppPaths, _ as default }; 57 | -------------------------------------------------------------------------------- /dist/xdg-app-paths.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rivy/js.xdg-app-paths/625c9f1ca0693c2c047dfb503affa486ea325b87/dist/xdg-app-paths.tgz -------------------------------------------------------------------------------- /eg/show-paths.cjs.js: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | // # spell-checker:ignore APPNAME 3 | /* eslint-env es6, node */ 4 | 'use strict'; 5 | 6 | const path = require('path'); 7 | 8 | /* eslint-disable no-console , security-node/detect-crlf , security-node/detect-non-literal-require-calls , security/detect-object-injection */ 9 | 10 | const xdgAppPathsModulePath = '../dist/cjs/mod.cjs.js'; 11 | 12 | const xdgAppPaths = require(xdgAppPathsModulePath); 13 | 14 | // Extend appPaths with a "log" location function 15 | // eslint-disable-next-line functional/immutable-data 16 | xdgAppPaths.log = function (dirOptions) { 17 | const self = xdgAppPaths; // * bind `self` to `appPaths` => avoids `this` variability due to caller context 18 | function typeOf(x) { 19 | // * use avoids circumvention of eslint variable tracking for `x` 20 | return typeof x; 21 | } 22 | 23 | if (typeOf(dirOptions) === 'boolean') { 24 | dirOptions = { isolated: dirOptions }; 25 | } 26 | 27 | if ( 28 | typeOf(dirOptions) !== 'object' || 29 | dirOptions === null || 30 | typeOf(dirOptions.isolated) !== 'boolean' 31 | ) { 32 | dirOptions = { isolated: self.$isolated() }; 33 | } 34 | 35 | return path.join(self.state(dirOptions), (dirOptions.isolated ? '' : self.$name() + '-') + 'log'); 36 | }; 37 | 38 | function showObjectEntries(obj) { 39 | var strings = []; 40 | Object.keys(obj).forEach((key) => { 41 | const value = obj[key]; 42 | const val = typeof value === 'function' ? value() : value; 43 | strings.push(key + ' = ' + val); 44 | }); 45 | return strings.join('\n'); 46 | } 47 | 48 | console.log({ appPaths: xdgAppPaths }); 49 | console.log(showObjectEntries(xdgAppPaths)); 50 | 51 | console.log('appPaths.log():', xdgAppPaths.log()); 52 | console.log('appPaths.log(false):', xdgAppPaths.log(false)); 53 | console.log('appPaths.log(true):', xdgAppPaths.log(true)); 54 | 55 | // eslint-disable-next-line functional/immutable-data 56 | delete process.env.XDG_CONFIG_HOME; 57 | // eslint-disable-next-line functional/no-let 58 | let p = require(xdgAppPathsModulePath)('dross'); 59 | 60 | console.log({ p }); 61 | console.log(showObjectEntries(p)); 62 | 63 | p = require(xdgAppPathsModulePath)({ suffix: '-nodejs' }); 64 | 65 | console.log({ p }); 66 | console.log(showObjectEntries(p)); 67 | 68 | p = require(xdgAppPathsModulePath)({ name: 'extraordinaire', suffix: '-nodejs' }); 69 | 70 | console.log({ p }); 71 | console.log(showObjectEntries(p)); 72 | 73 | p = require(xdgAppPathsModulePath)({ name: 'fluffy', isolated: false }); 74 | 75 | console.log({ p }); 76 | console.log(showObjectEntries(p)); 77 | 78 | /* eslint-enable no-console , security-node/detect-crlf , security-node/detect-non-literal-require-calls , security/detect-object-injection */ 79 | -------------------------------------------------------------------------------- /eg/show-paths.esm.mjs: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | // # spell-checker:ignore APPNAME 3 | /* eslint-env es6, node */ 4 | 'use strict'; 5 | 6 | import path from 'path'; 7 | import { inspect } from 'util'; 8 | 9 | /* eslint-disable functional/immutable-data , no-console , security-node/detect-crlf , security/detect-object-injection */ 10 | 11 | import xdgAppPaths from '../dist/cjs/esm-wrapper/mod.esm.js'; 12 | 13 | function objectEntries(obj) { 14 | const map = {}; 15 | Object.keys(obj).forEach((key) => { 16 | const value = obj[key]; 17 | const val = typeof value === 'function' ? value() : value; 18 | map[key] = val; 19 | }); 20 | return map; 21 | } 22 | 23 | // Extend appPaths with a "log" location function 24 | xdgAppPaths.log = function (dirOptions = null) { 25 | const self = xdgAppPaths; // * bind `self` to `appPaths` => avoids `this` variability due to caller context 26 | function typeOf(x) { 27 | // * use avoids circumvention of eslint variable tracking for `x` 28 | return typeof x; 29 | } 30 | 31 | if (typeOf(dirOptions) === 'boolean') { 32 | dirOptions = { isolated: dirOptions }; 33 | } 34 | 35 | if ( 36 | typeOf(dirOptions) !== 'object' || 37 | dirOptions === null || 38 | typeOf(dirOptions.isolated) !== 'boolean' 39 | ) { 40 | dirOptions = { isolated: self.$isolated() }; 41 | } 42 | 43 | return path.join(self.state(dirOptions), (dirOptions.isolated ? '' : self.$name() + '-') + 'log'); 44 | }; 45 | 46 | function showObjectEntries(obj) { 47 | var strings = []; 48 | Object.keys(obj).forEach((key) => { 49 | const value = obj[key]; 50 | const val = typeof value === 'function' ? value() : value; 51 | strings.push(key + ' = ' + val); 52 | }); 53 | return strings.join('\n'); 54 | } 55 | 56 | console.log({ appPaths: xdgAppPaths }); 57 | console.log(showObjectEntries(xdgAppPaths)); 58 | 59 | console.log('appPaths.log():', xdgAppPaths.log()); 60 | console.log('appPaths.log(false):', xdgAppPaths.log(false)); 61 | console.log('appPaths.log(true):', xdgAppPaths.log(true)); 62 | 63 | delete process.env.XDG_CONFIG_HOME; 64 | // eslint-disable-next-line functional/no-let 65 | let p = xdgAppPaths('dross'); 66 | 67 | console.log('p:', inspect(p)); 68 | console.log(objectEntries(p)); 69 | 70 | p = xdgAppPaths({ suffix: '-nodejs' }); 71 | 72 | console.log('p:', inspect(p)); 73 | console.log(objectEntries(p)); 74 | 75 | p = xdgAppPaths({ name: 'extraordinaire', suffix: '-nodejs' }); 76 | 77 | console.log('p:', inspect(p)); 78 | console.log(objectEntries(p)); 79 | 80 | p = xdgAppPaths({ name: 'fluffy', isolated: false }); 81 | 82 | console.log('p:', inspect(p)); 83 | console.log(objectEntries(p)); 84 | 85 | /* eslint-enable functional/immutable-data , no-console , security-node/detect-crlf , security/detect-object-injection */ 86 | -------------------------------------------------------------------------------- /eg/show-paths.local.deno.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | 3 | // spell-checker:ignore (names) Deno 4 | 5 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 6 | // @ts-ignore // deno-type URL import 7 | import * as path from 'https://deno.land/std@0.150.0/path/mod.ts'; 8 | 9 | /// 10 | 11 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 12 | // @ts-ignore // Deno alias to suppress other false-positive TS warnings 13 | const deno = Deno; 14 | 15 | const inspect = deno.inspect; 16 | 17 | /* eslint-disable @typescript-eslint/no-explicit-any , functional/immutable-data , no-console , security-node/detect-crlf , security/detect-object-injection */ 18 | 19 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 20 | // @ts-ignore // deno-type import 21 | import xdgAppPaths from '../src/mod.deno.ts'; 22 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 23 | // @ts-ignore // deno-type import 24 | import type { DirOptions, XDGAppPaths } from '../src/mod.deno.ts'; 25 | 26 | function objectEntries(obj: any) { 27 | const map: any = {}; 28 | Object.keys(obj).forEach((key) => { 29 | const value = obj[key]; 30 | const val = typeof value === 'function' ? value() : value; 31 | map[key] = val; 32 | }); 33 | return map; 34 | } 35 | 36 | // eslint-disable-next-line functional/prefer-readonly-type 37 | type XDGAppPathsWithLog = XDGAppPaths & { log: (dirOptions?: DirOptions | boolean) => string }; 38 | 39 | // Extend appPaths with a "log" location 40 | (xdgAppPaths as XDGAppPathsWithLog).log = function log(dirOptions?: DirOptions | boolean) { 41 | const self = xdgAppPaths; 42 | dirOptions = dirOptions ?? { isolated: self.$isolated() }; 43 | const isolated = typeof dirOptions === 'boolean' ? dirOptions : dirOptions.isolated || true; 44 | return path.join(self.state(isolated), (isolated ? '' : self.$name() + '-') + 'log'); 45 | }; 46 | 47 | console.log('appPaths:', inspect(xdgAppPaths)); 48 | console.log('appPaths.state(false):', xdgAppPaths.state(false)); 49 | console.log('appPaths.state(true):', xdgAppPaths.state(true)); 50 | console.log(objectEntries(xdgAppPaths)); 51 | console.log('appPaths.log(false):', (xdgAppPaths as XDGAppPathsWithLog).log(false)); 52 | console.log('appPaths.log(true):', (xdgAppPaths as XDGAppPathsWithLog).log(true)); 53 | 54 | const queryEnv = await Deno?.permissions?.query({ name: 'env' }); 55 | if (queryEnv?.state !== 'granted') { 56 | console.warn('ERROR: environment permissions are required (re-run with `--allow-env`)'); 57 | Deno.exit(1); 58 | } 59 | 60 | deno.env.delete('XDG_CONFIG_HOME'); 61 | // eslint-disable-next-line functional/no-let 62 | let p = xdgAppPaths('dross'); 63 | 64 | console.log('p:', inspect(p)); 65 | console.log(objectEntries(p)); 66 | 67 | p = xdgAppPaths({ suffix: '-nodejs' }); 68 | 69 | console.log('p:', inspect(p)); 70 | console.log(objectEntries(p)); 71 | 72 | p = xdgAppPaths({ name: 'extraordinaire', suffix: '-nodejs' }); 73 | 74 | console.log('p:', inspect(p)); 75 | console.log(objectEntries(p)); 76 | 77 | p = xdgAppPaths({ name: 'fluffy', isolated: false }); 78 | 79 | console.log('p:', inspect(p)); 80 | console.log(objectEntries(p)); 81 | 82 | /* eslint-enable @typescript-eslint/no-explicit-any , functional/immutable-data , no-console , security-node/detect-crlf , security/detect-object-injection */ 83 | -------------------------------------------------------------------------------- /eg/show-paths.remote(CDN).deno.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | 3 | // * `deno` permission requirements 4 | // --allow-env (transitive from 'xdg-app-paths') 5 | // --allow-read 6 | 7 | /* eslint-disable @typescript-eslint/ban-ts-comment , @typescript-eslint/no-explicit-any , functional/immutable-data , import/order , no-console , security-node/detect-crlf , security/detect-object-injection */ 8 | 9 | // @ts-ignore // deno-type URL import 10 | import * as path from 'https://deno.land/std@0.150.0/path/mod.ts'; 11 | 12 | /// 13 | 14 | // @ts-ignore // Deno alias to suppress other false-positive TS warnings 15 | const deno = Deno; 16 | 17 | const inspect = deno.inspect; 18 | 19 | // @ts-ignore // deno-type URL import 20 | import xdgAppPaths from 'https://cdn.jsdelivr.net/gh/rivy/js.xdg-app-paths@v8.1.0/src/mod.deno.ts'; 21 | // @ts-ignore // deno-type import 22 | import type { DirOptions, XDGAppPaths } from '../src/mod.deno.ts'; 23 | 24 | function objectEntries(obj: any) { 25 | const map: any = {}; 26 | Object.keys(obj).forEach((key) => { 27 | const value = obj[key]; 28 | const val = typeof value === 'function' ? value() : value; 29 | map[key] = val; 30 | }); 31 | return map; 32 | } 33 | 34 | // eslint-disable-next-line functional/prefer-readonly-type 35 | type XDGAppPathsWithLog = XDGAppPaths & { log: (dirOptions?: DirOptions | boolean) => string }; 36 | 37 | // Extend appPaths with a "log" location 38 | (xdgAppPaths as XDGAppPathsWithLog).log = function log(dirOptions?: DirOptions | boolean) { 39 | const self = xdgAppPaths; 40 | dirOptions = dirOptions ?? { isolated: self.$isolated() }; 41 | const isolated = typeof dirOptions === 'boolean' ? dirOptions : dirOptions.isolated || true; 42 | return path.join(self.state(isolated), (isolated ? '' : self.$name() + '-') + 'log'); 43 | }; 44 | 45 | console.log('appPaths:', inspect(xdgAppPaths)); 46 | console.log('appPaths.state(false):', xdgAppPaths.state(false)); 47 | console.log('appPaths.state(true):', xdgAppPaths.state(true)); 48 | console.log(objectEntries(xdgAppPaths)); 49 | console.log('appPaths.log(false):', (xdgAppPaths as XDGAppPathsWithLog).log(false)); 50 | console.log('appPaths.log(true):', (xdgAppPaths as XDGAppPathsWithLog).log(true)); 51 | 52 | const queryEnv = await Deno?.permissions?.query({ name: 'env' }); 53 | if (queryEnv?.state !== 'granted') { 54 | console.warn('ERROR: environment permissions are required (re-run with `--allow-env`)'); 55 | Deno.exit(1); 56 | } 57 | 58 | deno.env.delete('XDG_CONFIG_HOME'); 59 | // eslint-disable-next-line functional/no-let 60 | let p = xdgAppPaths('dross'); 61 | 62 | console.log('p:', inspect(p)); 63 | console.log(objectEntries(p)); 64 | 65 | p = xdgAppPaths({ suffix: '-nodejs' }); 66 | 67 | console.log('p:', inspect(p)); 68 | console.log(objectEntries(p)); 69 | 70 | p = xdgAppPaths({ name: 'extraordinaire', suffix: '-nodejs' }); 71 | 72 | console.log('p:', inspect(p)); 73 | console.log(objectEntries(p)); 74 | 75 | p = xdgAppPaths({ name: 'fluffy', isolated: false }); 76 | 77 | console.log('p:', inspect(p)); 78 | console.log(objectEntries(p)); 79 | 80 | /* eslint-enable @typescript-eslint/ban-ts-comment , @typescript-eslint/no-explicit-any , functional/immutable-data , import/order , no-console , security-node/detect-crlf , security/detect-object-injection */ 81 | -------------------------------------------------------------------------------- /eg/show-paths.remote.deno.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | 3 | // * `deno` permission requirements 4 | // --allow-env (transitive from 'xdg-app-paths') 5 | // --allow-read 6 | 7 | /* eslint-disable @typescript-eslint/ban-ts-comment , @typescript-eslint/no-explicit-any , functional/immutable-data , import/order , no-console , security-node/detect-crlf , security/detect-object-injection */ 8 | 9 | // @ts-ignore // deno-type URL import 10 | import * as path from 'https://deno.land/std@0.150.0/path/mod.ts'; 11 | 12 | /// 13 | 14 | // @ts-ignore // Deno alias to suppress other false-positive TS warnings 15 | const deno = Deno; 16 | 17 | const inspect = deno.inspect; 18 | 19 | // @ts-ignore // deno-type URL import 20 | import xdgAppPaths from 'https://deno.land/x/xdg_app_paths@v8.1.0/src/mod.deno.ts'; 21 | // @ts-ignore // deno-type import 22 | import type { DirOptions, XDGAppPaths } from '../src/mod.deno.ts'; 23 | 24 | function objectEntries(obj: any) { 25 | const map: any = {}; 26 | Object.keys(obj).forEach((key) => { 27 | const value = obj[key]; 28 | const val = typeof value === 'function' ? value() : value; 29 | map[key] = val; 30 | }); 31 | return map; 32 | } 33 | 34 | // eslint-disable-next-line functional/prefer-readonly-type 35 | type XDGAppPathsWithLog = XDGAppPaths & { log: (dirOptions?: DirOptions | boolean) => string }; 36 | 37 | // Extend appPaths with a "log" location 38 | (xdgAppPaths as XDGAppPathsWithLog).log = function log(dirOptions?: DirOptions | boolean) { 39 | const self = xdgAppPaths; 40 | dirOptions = dirOptions ?? { isolated: self.$isolated() }; 41 | const isolated = typeof dirOptions === 'boolean' ? dirOptions : dirOptions.isolated || true; 42 | return path.join(self.state(isolated), (isolated ? '' : self.$name() + '-') + 'log'); 43 | }; 44 | 45 | console.log('appPaths:', inspect(xdgAppPaths)); 46 | console.log('appPaths.state(false):', xdgAppPaths.state(false)); 47 | console.log('appPaths.state(true):', xdgAppPaths.state(true)); 48 | console.log(objectEntries(xdgAppPaths)); 49 | console.log('appPaths.log(false):', (xdgAppPaths as XDGAppPathsWithLog).log(false)); 50 | console.log('appPaths.log(true):', (xdgAppPaths as XDGAppPathsWithLog).log(true)); 51 | 52 | const queryEnv = await Deno?.permissions?.query({ name: 'env' }); 53 | if (queryEnv?.state !== 'granted') { 54 | console.warn('ERROR: environment permissions are required (re-run with `--allow-env`)'); 55 | Deno.exit(1); 56 | } 57 | 58 | deno.env.delete('XDG_CONFIG_HOME'); 59 | // eslint-disable-next-line functional/no-let 60 | let p = xdgAppPaths('dross'); 61 | 62 | console.log('p:', inspect(p)); 63 | console.log(objectEntries(p)); 64 | 65 | p = xdgAppPaths({ suffix: '-nodejs' }); 66 | 67 | console.log('p:', inspect(p)); 68 | console.log(objectEntries(p)); 69 | 70 | p = xdgAppPaths({ name: 'extraordinaire', suffix: '-nodejs' }); 71 | 72 | console.log('p:', inspect(p)); 73 | console.log(objectEntries(p)); 74 | 75 | p = xdgAppPaths({ name: 'fluffy', isolated: false }); 76 | 77 | console.log('p:', inspect(p)); 78 | console.log(objectEntries(p)); 79 | 80 | /* eslint-enable @typescript-eslint/ban-ts-comment , @typescript-eslint/no-explicit-any , functional/immutable-data , import/order , no-console , security-node/detect-crlf , security/detect-object-injection */ 81 | -------------------------------------------------------------------------------- /eg/show-paths.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | 3 | import path from 'path'; 4 | import { inspect } from 'util'; 5 | 6 | /* eslint-disable @typescript-eslint/no-explicit-any , functional/immutable-data , no-console , security-node/detect-crlf , security/detect-object-injection */ 7 | 8 | import xdgAppPaths from '../dist/cjs/mod.cjs'; 9 | import type { DirOptions, XDGAppPaths } from '../src/mod.esm'; 10 | 11 | function objectEntries(obj: any) { 12 | const map: any = {}; 13 | Object.keys(obj).forEach((key) => { 14 | const value = obj[key]; 15 | const val = typeof value === 'function' ? value() : value; 16 | map[key] = val; 17 | }); 18 | return map; 19 | } 20 | 21 | // eslint-disable-next-line functional/prefer-readonly-type 22 | type XDGAppPathsWithLog = XDGAppPaths & { log: (dirOptions?: DirOptions | boolean) => string }; 23 | 24 | // Extend appPaths with a "log" location 25 | (xdgAppPaths as XDGAppPathsWithLog).log = function log(dirOptions?: DirOptions | boolean) { 26 | const self = xdgAppPaths; 27 | dirOptions = dirOptions ?? { isolated: self.$isolated() }; 28 | const isolated = typeof dirOptions === 'boolean' ? dirOptions : dirOptions.isolated || true; 29 | return path.join(self.state(isolated), (isolated ? '' : self.$name() + '-') + 'log'); 30 | }; 31 | 32 | console.log('appPaths:', inspect(xdgAppPaths)); 33 | console.log('appPaths.state(false):', xdgAppPaths.state(false)); 34 | console.log('appPaths.state(true):', xdgAppPaths.state(true)); 35 | console.log(objectEntries(xdgAppPaths)); 36 | console.log('appPaths.log(false):', (xdgAppPaths as XDGAppPathsWithLog).log(false)); 37 | console.log('appPaths.log(true):', (xdgAppPaths as XDGAppPathsWithLog).log(true)); 38 | 39 | delete process.env.XDG_CONFIG_HOME; 40 | // eslint-disable-next-line functional/no-let 41 | let p = xdgAppPaths('dross'); 42 | 43 | console.log('p:', inspect(p)); 44 | console.log(objectEntries(p)); 45 | 46 | p = xdgAppPaths({ suffix: '-nodejs' }); 47 | 48 | console.log('p:', inspect(p)); 49 | console.log(objectEntries(p)); 50 | 51 | p = xdgAppPaths({ name: 'extraordinaire', suffix: '-nodejs' }); 52 | 53 | console.log('p:', inspect(p)); 54 | console.log(objectEntries(p)); 55 | 56 | p = xdgAppPaths({ name: 'fluffy', isolated: false }); 57 | 58 | console.log('p:', inspect(p)); 59 | console.log(objectEntries(p)); 60 | 61 | /* eslint-enable @typescript-eslint/no-explicit-any , functional/immutable-data , no-console , security-node/detect-crlf , security/detect-object-injection */ 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xdg-app-paths", 3 | "version": "8.3.0", 4 | "description": "Determine (XDG-compatible) paths for storing application files (cache, config, data, etc)", 5 | "license": "MIT", 6 | "repository": "rivy/js.xdg-app-paths", 7 | "author": { 8 | "name": "Roy Ivy III", 9 | "email": "rivy.dev@gmail.com" 10 | }, 11 | "engines": { 12 | "node": ">= 4.0" 13 | }, 14 | "packageManager": "yarn@1.22.19", 15 | "files": [ 16 | "cjs", 17 | "dist/cjs", 18 | "dist/types", 19 | "CHANGELOG.mkd", 20 | "LICENSE", 21 | "README.md", 22 | "package.json" 23 | ], 24 | "type": "commonjs", 25 | "main": "./dist/cjs/mod.cjs.js", 26 | "module": "./dist/cjs/esm-wrapper/mod.esm.js", 27 | "types": "./dist/types/mod.d.ts", 28 | "exports": { 29 | ".": { 30 | "deno": "./src/mod.deno.ts", 31 | "import": "./dist/cjs/esm-wrapper/mod.esm.js", 32 | "require": "./dist/cjs/mod.cjs.js", 33 | "types": "./dist/types/mod.d.ts", 34 | "default": "./dist/cjs/mod.cjs.js" 35 | }, 36 | "./package.json": "./package.json", 37 | "./cjs": { 38 | "require": "./dist/cjs/mod.cjs.js", 39 | "types": "./dist/cjs/mod.cjs.d.ts" 40 | } 41 | }, 42 | "keywords": [ 43 | "appdir", 44 | "application", 45 | "cache", 46 | "common", 47 | "config", 48 | "cross-platform", 49 | "data", 50 | "directory", 51 | "environment", 52 | "linux", 53 | "mac", 54 | "macos", 55 | "node4", 56 | "node6", 57 | "node-v4", 58 | "node-v6", 59 | "osx", 60 | "path", 61 | "paths", 62 | "portable", 63 | "runtime", 64 | "state", 65 | "unix", 66 | "user", 67 | "windows", 68 | "xdg" 69 | ], 70 | "scripts": { 71 | "# build # build/compile package": "", 72 | "build": "run-s --silent \"build:*\"", 73 | "build:cjs": "exec-if-updated --source package.json --source tsconfig.json --source \"tsconfig/**\" --source \"rollup.*.config.js\" --source \"src/**\" --target build/.targets/build-cjs.succeeded \"run-s -n rebuild:cjs\"", 74 | "build:esm": "exec-if-updated --source package.json --source tsconfig.json --source \"tsconfig/**\" --source \"rollup.*.config.js\" --source \"src/**\" --target build/.targets/build-esm.succeeded \"run-s -n rebuild:esm\"", 75 | "build:umd": "exec-if-updated --source package.json --source tsconfig.json --source \"tsconfig/**\" --source \"rollup.*.config.js\" --source \"src/**\" --target build/.targets/build-umd.succeeded \"run-s -n rebuild:umd\"", 76 | "build:lab": "exec-if-updated --source package.json --source tsconfig.json --source \"tsconfig/**\" --source \"rollup.*.config.js\" --source \"src/**\" --target build/.targets/build-lab.succeeded \"run-s -n rebuild:lab\"", 77 | "build:types": "exec-if-updated --source package.json --source tsconfig.json --source \"tsconfig/**\" --source \"rollup.*.config.js\" --source \"src/**\" --target build/.targets/build-types.succeeded \"run-s -n rebuild:types\"", 78 | "# clean # remove build artifacts": "", 79 | "clean": "shx rm -fr build dist", 80 | "# coverage # calculate and display (or send) code coverage [alias: 'cov']": "", 81 | "coverage": "run-s --silent +:max-node-8 && shx echo \"[coverage] WARN Code coverage skipped [for NodeJS < v10]\" 1>&2 || run-s \"+:coverage\"", 82 | "cov": "run-s coverage", 83 | "cov:html": "nyc report --reporter=html --report-dir=.coverage", 84 | "#* cov:send # use `--cov-send=...` to pass options to coverage uploader": "", 85 | "cov:send": "shx mkdir -p .coverage && nyc report --reporter=text-lcov > \".coverage/@coverage.lcov\" && cross-env-shell codecov --disable=gcov --file=\".coverage/@coverage.lcov\" $npm_config_cov_send", 86 | "cov:text": "nyc report", 87 | "cov:view": "run-s cov:html && cd .coverage && open-cli index.html", 88 | "dist": "run-s update", 89 | "# fix # fix package issues (automated/non-interactive)": "", 90 | "fix": "run-s fix:*", 91 | "# fix:lint # fix ESLint issues": "", 92 | "fix:lint": "eslint . --fix", 93 | "# fix:style # fix Prettier formatting issues": "", 94 | "fix:style": "prettier . --write --list-different", 95 | "# help # display help": "", 96 | "help": "run-s --silent _:help", 97 | "# lint # check for package code 'lint'": "", 98 | "lint": "run-s --silent +:max-node-8 && shx echo \"[lint] WARN Lint checks skipped [for NodeJS < v10]\" 1>&2 || run-p --print-name \"lint:*\"", 99 | "# lint:audit # check for `npm audit` violations in project code": "", 100 | "lint:audit": "run-s --silent -- npm audit --omit dev", 101 | "# lint:commits # check for commit flaws (using `commitlint` and `cspell`)": "", 102 | "lint:commits": "run-p --silent \"_:lint:commits:new:*\"", 103 | "# lint:editorconfig # check for EditorConfig format flaws (using `editorconfig-checker`)": "", 104 | "lint:editorconfig": "editorconfig-checker -config .ecrc.JS.json", 105 | "# lint:lint # check for code 'lint' (using `eslint`)": "", 106 | "lint:lint": "eslint .", 107 | "# lint:markdown # check for markdown errors (using `remark`)": "", 108 | "lint:markdown": "remark --quiet .", 109 | "# lint:spell # check for spelling errors (using `cspell`)": "", 110 | "lint:spell": "cspell {eg,examples,src,test}/**/* CHANGELOG{,.md,.mkd} README{,.md,.mkd} --no-summary --config \".vscode/cspell.json\"", 111 | "# lint:style # check for format imperfections (using `prettier`)": "", 112 | "lint:style": "prettier . --check --loglevel warn", 113 | "# prerelease # clean, rebuild, and fully test (useful prior to publish/release)": "", 114 | "prerelease": "run-s clean update verify", 115 | "# realclean # remove all generated files": "", 116 | "realclean": "run-s clean && shx rm -fr .coverage .nyc_output", 117 | "# rebuild # clean and (re-)build project": "", 118 | "rebuild": "run-s clean build", 119 | "rebuild:all": "run-s clean build update", 120 | "rebuild:cjs": "shx rm -fr build/cjs && tsc -p tsconfig/tsconfig.cjs.json && shx cp -r src/esm-wrapper build/cjs/src && shx mkdir -p build/.targets && shx touch build/.targets/build-cjs.succeeded", 121 | "rebuild:esm": "shx rm -fr build/esm && tsc -p tsconfig/tsconfig.esm.json && shx cp src/esm-wrapper/package.json build/esm/src && shx mkdir -p build/.targets && shx touch build/.targets/build-esm.succeeded", 122 | "rebuild:umd": "shx rm -fr build/umd && tsc -p tsconfig/tsconfig.umd.json && shx mkdir -p build/.targets && shx touch build/.targets/build-umd.succeeded", 123 | "rebuild:lab": "shx rm -fr build/lab && tsc -p tsconfig/tsconfig.lab.json && shx cp -r src/esm-wrapper build/lab/src && shx mkdir -p build/.targets && shx touch build/.targets/build-lab.succeeded", 124 | "rebuild:types": "shx rm -fr build/types && tsc -p tsconfig/tsconfig.types.json && shx mkdir -p build/.targets && shx touch build/.targets/build-types.succeeded", 125 | "# refresh # clean and rebuild/regenerate all project artifacts": "", 126 | "refresh": "run-s rebuild:all", 127 | "# refresh:dist # clean, rebuild, and regenerate project distribution": "", 128 | "refresh:dist": "run-s rebuild update:dist", 129 | "# retest # clean and (re-)test project": "", 130 | "retest": "run-s clean test", 131 | "# reset:hard # remove *all* generated files and reinstall dependencies": "", 132 | "reset:hard": "git clean -dfx && git reset --hard && npm install", 133 | "# show:deps # show package dependencies": "", 134 | "show:deps": "run-s --silent _:show:deps:prod _:show:deps:dev || shx true", 135 | "# test # test package": "", 136 | "test": "run-s --silent lint update:dist && run-p test:*", 137 | "# test:code # test package code (use `--test-code=...` to pass options to testing harness)": "", 138 | "test:code": "run-s --silent +:max-node-8 && cross-env-shell ava $npm_config_test_code || ( run-s --silent +:min-node-10 && cross-env-shell nyc --silent ava $npm_config_test_code )", 139 | "# test:types # test for type declaration errors (using `tsd`)": "", 140 | "test:types": "run-s --silent +:max-node-8 && shx echo \"[test:types] WARN Type testing skipped [for NodeJS < v10]\" 1>&2 || tsd", 141 | "# update # update/prepare for distribution [alias: 'dist']": "", 142 | "update": "run-s update:changelog update:dist", 143 | "# update:changelog # update CHANGELOG (using `git changelog ...`)": "", 144 | "update:changelog": "run-s --silent _:update:changelog && git diff --quiet --exit-code CHANGELOG.mkd || shx echo \"[update] info CHANGELOG updated\"", 145 | "# update:dist # update distribution content": "", 146 | "update:dist": "run-s --silent build && exec-if-updated --source \"build/**\" --target \"dist/**\" --target build/.targets/update-dist.succeeded \"run-s --silent _:update:dist:rebuild\"", 147 | "# verify # fully (and verbosely) test package": "", 148 | "verify": "cross-env npm_config_test_dist=true npm_config_test=--verbose run-s test", 149 | "## +:... == sub-scripts (may run 'visibly', but not user-facing)": "", 150 | "+:coverage": "run-s build test:code && ( is-ci && run-s cov:send ) || ( run-s --silent _:is-not-ci && run-s cov:view )", 151 | "+:max-node-8": "is-node-not-modern 10", 152 | "+:min-node-10": "is-node-modern 10", 153 | "## _:... == sub-scripts ('hidden'; generally should be run 'silently' using `run-s/run-p --silent ...`": "", 154 | "_:debug:env": "node -e \"console.log({env: process.env})\"", 155 | "_:exists:git-changelog": "node -e \"if (!require('command-exists').sync('git-changelog')){process.exit(1);};\" || ( shx echo \"WARN `git-changelog` missing (try `go get -u github.com/rivy-go/git-changelog/cmd/git-changelog`)\" & exit 1 )", 156 | "* _:help # print usage/TARGETs by matching lines containing leading double-quoted text like `# TARGET_NAME # HELP_TEXT`": "", 157 | "_:help": "< package.json node -e \"s = {p:'',e:'npm'}; if (new String(process.env.npm_execpath).match(/yarn.js$/)) { s = {p:'\\n',e:'yarn'}; }; console.log('%sUsage: \\`\\x1b[2m%s run TARGET\\x1b[m\\` or \\`\\x1b[2mnpx run-s TARGET [TARGET..]\\x1b[m\\`\\n\\nTARGETs:\\n', s.p, s.e); re = /^.*?\\x22(?:#\\s*)(\\w[^#\\x22]*)\\s+#+\\s+([^\\x22]+?)(\\s+#+)?\\x22.*$/; require('readline').createInterface({ input: process.stdin, output: process.stdout, terminal: false }).on('line', function(line){ if (match = re.exec(line)) { console.log('\\x1b[0;32m%s\\x1b[m %s', match[1].padEnd(19), match[2]); } }).on('close', () => { /^win/i.test(process.platform) || console.log(); });\"", 158 | "_:is-not-ci": "is-ci && exit 1 || exit 0", 159 | "_:lint:commits:all:spell": "node -e \"result=require('child_process').spawnSync('git log --color=never | cspell stdin --no-summary --config \".vscode/cspell.json\"',{shell:true,encoding:'utf-8'}); if (result.status != 0) {console.error('[cspell] ERR! Unknown words in commit(s)\\n'+result.stdout+'\\n'+result.stderr); process.exit(1);} else {console.log(result.stdout);};\"", 160 | "* _:lint:commits:new:... * note: review from 'origin/last' or tag just prior to version-sorted latest, with fallback to first commit": "", 161 | "_:lint:commits:new:commitlint": "node -e \"result=require('child_process').spawnSync('( git tag --list [#v]* --contains origin/last --sort=v:refname || shx true ) && ( git describe --tags --abbrev=0 HEAD~1 || shx true ) && ( git rev-list --max-parents=0 HEAD --abbrev-commit --abbrev=16 || shx true )',{shell:true,encoding:'utf-8'}); o=result.stdout.split(/\\r?\\n/).filter((s)=>!!s); vs=o; v=vs[0]; result=require('child_process').spawnSync('commitlint --config .commitlint.config.js --from '+v,{shell:true,encoding:'utf-8'}); if (result.status != 0) {console.error('[commitlint] ERR! Flawed commit(s) found (within \\'%s..HEAD\\')\\n'+result.stdout+'\\n'+result.stderr, v); process.exit(1);} else { (result.stdout.length > 0) && console.log(result.stdout);};\" || shx true", 162 | "_:lint:commits:new:spell": "node -e \"result=require('child_process').spawnSync('( git tag --list [#v]* --contains origin/last --sort=v:refname || shx true ) && ( git describe --tags --abbrev=0 HEAD~1 || shx true ) && ( git rev-list --max-parents=0 HEAD --abbrev-commit --abbrev=16 || shx true )',{shell:true,encoding:'utf-8'}); o=result.stdout.split(/\\r?\\n/).filter((s)=>!!s); vs=o; v=vs[0]; result=require('child_process').spawnSync('git log '+v+'.. --color=never | cspell stdin --no-summary --config \".vscode/cspell.json\"',{shell:true,encoding:'utf-8'}); if (result.status != 0) {console.error('[cspell] ERR! Unknown words in commit(s) (within \\'%s..HEAD\\')\\n'+result.stdout+'\\n'+result.stderr, v); process.exit(1);} else {(result.stdout.length > 0) && console.log(result.stdout);};\" || shx true", 163 | "_:show:deps:dev": "npm --silent ls --only development || shx true", 164 | "_:show:deps:prod": "npm --silent ls --only production || shx true", 165 | "_:vcs-clean": "git diff --quiet", 166 | "_:vcs-clean-err": "run-s --silent _:vcs-clean || ( shx echo \"[vcs] ERR! Uncommitted changes\" 1>&2 & exit 1 )", 167 | "_:vcs-strictly-clean": "git status --porcelain | node -e \"process.stdin.on('data',function(_){process.exit(1);});\"", 168 | "_:vcs-strictly-clean-err": "run-s --silent _:vcs-strictly-clean || ( shx echo \"[vcs] ERR! Uncommitted changes and/or untracked files\" 1>&2 & exit 1 )", 169 | "_:update:changelog": "run-s --silent _:exists:git-changelog && git changelog > CHANGELOG.mkd || shx echo \"[update] WARN CHANGELOG not updated\" 1>&2", 170 | "_:update:dist.build": "shx rm -fr dist/cjs dist/esm && shx mkdir -p dist/cjs dist/esm && shx cp -r build/cjs/src/* dist/cjs && shx cp -r build/esm/src/* dist/esm", 171 | "_:update:dist.normalizeEOL": "eolConverter lf dist/**/*.{cjs,js,mjs,ts,json}", 172 | "_:update:dist.pack": "node -e \"delete process.env.npm_config_dry_run; name=require('./package.json').name; name=name.replace(/^@/,'').replace('/','-'); result=require('child_process').spawnSync('npm pack && shx mkdir -p dist && shx mv '+name+'-*.tgz dist/'+name+'.tgz',{shell:true,encoding:'utf-8'}); if (result.status != 0) {console.error('[update] ERR! Unable to package (into *.tgz) for distribution\\n'+result.stdout+'\\n'+result.stderr); process.exit(1);} else {console.log(result.stdout);};\"", 173 | "_:update:dist.types": "shx mkdir -p dist && shx rm -fr dist/types && rollup --config .rollup.config.types.js && replace-in-file \"export { _default as default }\" \"export = _default\" dist/types/mod.cjs.d.ts --quiet && shx mkdir -p dist/cjs && shx cp dist/types/*.cjs.d.ts dist/cjs", 174 | "_:update:dist:rebuild": "shx rm -fr dist && run-s --silent _:update:dist.build _:update:dist.types _:update:dist.normalizeEOL _:update:dist.pack && shx mkdir -p dist/.targets && shx touch build/.targets/update-dist.succeeded", 175 | "_:version:spell:changelog_update": "run-s --silent _:exists:git-changelog && git changelog -u | cspell stdin --config \".vscode/cspell.json\" || shx echo \"[lint] WARN CHANGELOG update `cspell` exception\" 1>&2", 176 | "_:version:update:changelog": "run-s --silent _:exists:git-changelog && node -e \"v=require('./package.json').version; result=require('child_process').spawnSync('git changelog --next-tag-now --next-tag v'+v,{shell:true,encoding:'utf-8'}); if (result.status != 0) {console.error('ERR! '+result.stderr); process.exit(1);} else {m='fs';require(m).writeFileSync('CHANGELOG.mkd',result.stdout);};\" || shx echo \"[version] WARN CHANGELOG not updated\" 1>&2", 177 | "## npm lifecycle scripts ##": "", 178 | "prepublishOnly": "run-s clean update && cross-env npm_config_test_dist=true npm run test && run-s --silent update _:vcs-strictly-clean-err", 179 | "## npm-version scripts ##": "", 180 | "preversion": "run-s --silent _:version:spell:changelog_update && cross-env npm_config_test_dist=true npm run test", 181 | "version": "run-s --silent _:version:update:changelog && run-s lint:spell && run-s --silent update:dist && git add CHANGELOG.mkd dist" 182 | }, 183 | "dependencies": { 184 | "xdg-portable": "^10.6.0" 185 | }, 186 | "devDependencies:#": "* for testing, Node-v6 requires ava < v2 and nyc < v15", 187 | "devDependencies": { 188 | "@ava/typescript": "^1.1.1", 189 | "@commitlint/cli": "^11.0.0", 190 | "@commitlint/config-conventional": "^11.0.0", 191 | "@istanbuljs/nyc-config-typescript": "^1.0.1", 192 | "@types/node": "^14.14.20", 193 | "@typescript-eslint/eslint-plugin": "^4", 194 | "@typescript-eslint/parser": "^4", 195 | "ava": "^3.15.0", 196 | "codecov": "^3.5.0", 197 | "command-exists": "^1.2.9", 198 | "cross-env": "^7.0.3", 199 | "cross-spawn": "^7.0.3", 200 | "cspell": "^4.2.7", 201 | "editorconfig-checker": "^3.3.0", 202 | "eol-converter-cli": "^1.0.8", 203 | "eslint": "^7", 204 | "eslint-config-prettier": "^7", 205 | "eslint-plugin-eslint-comments": "^3", 206 | "eslint-plugin-functional": "^3", 207 | "eslint-plugin-import": "^2", 208 | "eslint-plugin-security": "^1", 209 | "eslint-plugin-security-node": "^1", 210 | "exec-if-updated": "https://cdn.jsdelivr.net/gh/rivy/js-cli.exec-if-updated@2.2.0/dist/pkg/exec-if-updated.tgz", 211 | "is-ci": "^2.0.0", 212 | "is-node-modern": "^1.0.0", 213 | "npm-run-all": "^4.1.5", 214 | "nyc": "^15.1.0", 215 | "open-cli": ">=6.0 <7.0", 216 | "prettier": "^2.1.1", 217 | "remark-cli": "=9.0.0", 218 | "remark-footnotes": "^3.0.0", 219 | "remark-preset-lint-consistent": "^4.0.0", 220 | "remark-preset-lint-markdown-style-guide": "^4.0.0", 221 | "remark-preset-lint-recommended": "^5.0.0", 222 | "remark-retext": "^4.0.0", 223 | "replace-in-file": "=6.3.0", 224 | "retext-english": "^3.0.4", 225 | "retext-passive": "^3.0.0", 226 | "retext-repeated-words": "^3.0.0", 227 | "retext-sentence-spacing": "^4.0.0", 228 | "retext-syntax-urls": "^2.0.0", 229 | "rollup": "^2.36.1", 230 | "rollup-plugin-dts": "^2.0.1", 231 | "rollup-plugin-typescript2": "^0.29.0", 232 | "shx": "^0.3.3", 233 | "ts-node": "^9.0.0", 234 | "tsd": "^0.14.0", 235 | "typedoc": "^0.20.27", 236 | "typescript": "~4.2.0", 237 | "unified": "^9.2.0" 238 | }, 239 | "optionalDependencies:#": "* 'fsevents' included to avoid `npm ci` errors with early npm versions; ref: ", 240 | "optionalDependencies": { 241 | "fsevents": "*" 242 | }, 243 | "ava": { 244 | "files": [ 245 | "!**/*.test-d.ts" 246 | ], 247 | "timeout": "60s", 248 | "typescript": { 249 | "rewritePaths": { 250 | "src/": "build/lab/src/" 251 | } 252 | } 253 | }, 254 | "nyc": { 255 | "extends": "@istanbuljs/nyc-config-typescript", 256 | "exclude": [ 257 | "build/cjs/**", 258 | "build/esm/**", 259 | "build/umd/**", 260 | "dist/**", 261 | "eg/**", 262 | "test/**", 263 | "**/*.test.*", 264 | "**/*.spec.*" 265 | ], 266 | "reporter": [ 267 | "html", 268 | "text" 269 | ], 270 | "lines": "100", 271 | "branches": "96", 272 | "statements": "100" 273 | }, 274 | "tsd": { 275 | "directory": "test" 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /src/esm-wrapper/mod.esm.js: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | 3 | import _ from '../mod.cjs.js'; 4 | export * from '../mod.cjs.js'; 5 | export default _; 6 | -------------------------------------------------------------------------------- /src/esm-wrapper/package.json: -------------------------------------------------------------------------------- 1 | {"type": "module"} 2 | -------------------------------------------------------------------------------- /src/lib/XDGAppPaths.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | // # spell-checker:ignore APPDATA LOCALAPPDATA MacOS tempdir 3 | /* eslint-env es6, node */ 4 | 'use strict'; 5 | 6 | import { Platform } from '../platform-adapters/_base.js'; 7 | 8 | // XDG references 9 | // # ref: @@ 10 | // # ref: @@ 11 | // # ref: @@ 12 | // # ref: @@ 13 | // # ref: @@ 14 | 15 | /** Configuration options supplied to `XDGAppPaths` methods */ 16 | // eslint-disable-next-line functional/prefer-type-literal 17 | interface DirOptions { 18 | /** Isolation flag; used to override the default isolation mode, when needed. */ 19 | readonly isolated?: boolean | null; 20 | } 21 | 22 | /** Configuration options supplied when constructing `XDGAppPaths` */ 23 | // eslint-disable-next-line functional/prefer-type-literal 24 | interface Options { 25 | /** Name of the application; used to generate isolated application paths. 26 | > When missing (`undefined`), `null`, or empty (`''`), it is generated automatically from the process main file name, where determinable. 27 | > "$eval" is used as a final fallback value when the application name cannot otherwise be determined. 28 | */ 29 | readonly name?: string | null; 30 | /** Suffix which is appended to the application name when generating the application paths. */ 31 | readonly suffix?: string | null; 32 | /** Default isolation flag (used when no isolation flag is supplied for `DirOptions`). */ 33 | readonly isolated?: boolean | null; 34 | } 35 | 36 | /** `XDGAppPaths` (API) - Determine (XDG-compatible) paths for storing application files (cache, config, data, etc) */ 37 | // eslint-disable-next-line functional/prefer-type-literal 38 | interface XDGAppPaths { 39 | /** Create an `XDGAppPaths` object (a preceding `new` is optional). */ 40 | (options?: Options | string): XDGAppPaths; 41 | 42 | /** Create an `XDGAppPaths` object (`new` is optional). */ 43 | // eslint-disable-next-line @typescript-eslint/no-misused-new 44 | new (options?: Options | string): XDGAppPaths; 45 | 46 | /* eslint-disable functional/no-method-signature */ 47 | 48 | /** Returns the directory for non-essential data files. 49 | > Deletion of the data contained here might cause an application to slow down. 50 | */ 51 | cache(dirOptions?: DirOptions | boolean): string; 52 | 53 | /** Returns the directory for config files. 54 | > Deletion of the data contained here might require the user to reconfigure an application. 55 | */ 56 | config(dirOptions?: DirOptions | boolean): string; 57 | 58 | /** Returns the directory for data files. 59 | > Deletion of the data contained here might force the user to restore from backups. 60 | */ 61 | data(dirOptions?: DirOptions | boolean): string; 62 | 63 | /** Returns the directory for runtime files; may return `undefined`. 64 | > Deletion of the data contained here might interfere with a currently executing application but should have no effect on future executions. 65 | */ 66 | runtime(dirOptions?: DirOptions | boolean): string | undefined; 67 | 68 | /** Returns the directory for state files. 69 | > Deletion of the data contained here should not materially interfere with execution of an application. 70 | */ 71 | state(dirOptions?: DirOptions | boolean): string; 72 | 73 | /** Returns a priority-sorted list of possible directories for configuration file storage (includes `paths.config()` as the first entry). */ 74 | configDirs(dirOptions?: DirOptions | boolean): readonly string[]; 75 | 76 | /** Returns a priority-sorted list of possible directories for data file storage (includes `paths.data()` as the first entry). */ 77 | dataDirs(dirOptions?: DirOptions | boolean): readonly string[]; 78 | 79 | /** Application name used for path construction (from supplied configuration or auto-generated). */ 80 | $name(): string; 81 | /** Default isolation mode used by the particular `XDGAppPaths` instance. */ 82 | $isolated(): boolean; 83 | 84 | /* eslint-enable functional/no-method-signature */ 85 | } 86 | 87 | function isBoolean(t: T | boolean): t is boolean { 88 | return typeOf(t) === 'boolean'; 89 | } 90 | 91 | function isObject(t: T | Record): t is Record { 92 | return typeOf(t) === 'object'; 93 | } 94 | 95 | function isString(t: T): boolean { 96 | return typeOf(t) === 'string'; 97 | } 98 | 99 | function typeOf(t: T): string { 100 | return typeof t; 101 | } 102 | 103 | function Adapt(adapter_: Platform.Adapter): { readonly XDGAppPaths: XDGAppPaths } { 104 | const { meta, path, xdg } = adapter_; 105 | // eslint-disable-next-line functional/no-class 106 | class XDGAppPaths_ { 107 | constructor(options_: Options | string = {}) { 108 | function XDGAppPaths(options: Options | string = {}): XDGAppPaths { 109 | return new XDGAppPaths_(options) as XDGAppPaths; 110 | } 111 | 112 | const options = (isObject(options_) ? options_ : { name: options_ }) as Options; 113 | 114 | const suffix = options.suffix ?? ''; 115 | const isolated_ = options.isolated ?? true; 116 | 117 | // derive a suitable application name 118 | const namePriorityList: ReadonlyArray = [ 119 | options.name, 120 | meta.pkgMainFilename(), 121 | meta.mainFilename(), 122 | ]; 123 | const nameFallback = '$eval'; 124 | const name = path.parse( 125 | (namePriorityList.find((e) => isString(e)) ?? nameFallback) + suffix 126 | ).name; 127 | 128 | XDGAppPaths.$name = function $name() { 129 | return name; 130 | }; 131 | XDGAppPaths.$isolated = function $isolated() { 132 | return isolated_; 133 | }; 134 | 135 | function isIsolated(dirOptions?: DirOptions | boolean): boolean { 136 | dirOptions = dirOptions ?? { isolated: isolated_ }; 137 | const isolated = isBoolean(dirOptions) ? dirOptions : dirOptions.isolated ?? isolated_; 138 | return isolated; 139 | } 140 | 141 | function finalPathSegment(dirOptions?: DirOptions | boolean): string { 142 | return isIsolated(dirOptions) ? name : ''; 143 | } 144 | 145 | XDGAppPaths.cache = function cache(dirOptions?: DirOptions | boolean) { 146 | return path.join(xdg.cache(), finalPathSegment(dirOptions)); 147 | }; 148 | 149 | XDGAppPaths.config = function config(dirOptions?: DirOptions | boolean) { 150 | return path.join(xdg.config(), finalPathSegment(dirOptions)); 151 | }; 152 | 153 | XDGAppPaths.data = function data(dirOptions?: DirOptions | boolean) { 154 | return path.join(xdg.data(), finalPathSegment(dirOptions)); 155 | }; 156 | 157 | XDGAppPaths.runtime = function runtime(dirOptions?: DirOptions | boolean) { 158 | return xdg.runtime() 159 | ? path.join(xdg.runtime() as string, finalPathSegment(dirOptions)) 160 | : void 0; 161 | }; 162 | 163 | XDGAppPaths.state = function state(dirOptions?: DirOptions | boolean) { 164 | return path.join(xdg.state(), finalPathSegment(dirOptions)); 165 | }; 166 | 167 | XDGAppPaths.configDirs = function configDirs(dirOptions?: DirOptions | boolean) { 168 | return xdg 169 | .configDirs() 170 | .map((s) => path.join(s, finalPathSegment(dirOptions))) as readonly string[]; 171 | }; 172 | 173 | XDGAppPaths.dataDirs = function dataDirs(dirOptions?: DirOptions | boolean) { 174 | return xdg 175 | .dataDirs() 176 | .map((s) => path.join(s, finalPathSegment(dirOptions))) as readonly string[]; 177 | }; 178 | 179 | return XDGAppPaths as XDGAppPaths; 180 | } 181 | } 182 | 183 | return { XDGAppPaths: new XDGAppPaths_() as XDGAppPaths }; 184 | } 185 | 186 | export type { DirOptions, Options, XDGAppPaths }; 187 | export { Adapt }; 188 | -------------------------------------------------------------------------------- /src/mod.cjs.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | 3 | import { Adapt } from './lib/XDGAppPaths.js'; 4 | import type { XDGAppPaths } from './lib/XDGAppPaths.js'; 5 | import { adapter } from './platform-adapters/node.js'; 6 | 7 | export = Adapt(adapter).XDGAppPaths as XDGAppPaths; 8 | -------------------------------------------------------------------------------- /src/mod.deno.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | // spell-checker:ignore Deno 3 | 4 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 5 | // @ts-ignore 6 | import { Adapt } from '../dist/esm/lib/XDGAppPaths.js'; 7 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 8 | // @ts-ignore 9 | import { DirOptions, Options, XDGAppPaths } from '../dist/types/mod.d.ts'; 10 | 11 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 12 | // @ts-ignore 13 | import { adapter } from './platform-adapters/deno.deno.ts'; 14 | 15 | const _: XDGAppPaths = Adapt(adapter).XDGAppPaths as XDGAppPaths; 16 | 17 | export type { DirOptions, Options, XDGAppPaths }; 18 | export default _; 19 | -------------------------------------------------------------------------------- /src/mod.esm.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | 3 | import { Adapt } from './lib/XDGAppPaths.js'; 4 | import type { DirOptions, Options, XDGAppPaths } from './lib/XDGAppPaths.js'; 5 | import { adapter } from './platform-adapters/node.js'; 6 | 7 | const _: XDGAppPaths = Adapt(adapter).XDGAppPaths as XDGAppPaths; 8 | 9 | export type { DirOptions, Options, XDGAppPaths }; 10 | export default _; 11 | -------------------------------------------------------------------------------- /src/mod.test.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | 3 | import test from 'ava'; 4 | 5 | import mESM from './mod.esm.js'; 6 | 7 | // eslint-disable-next-line @typescript-eslint/no-var-requires 8 | const mCJS = require('./mod.cjs.js'); 9 | 10 | test('CJS <=> ESM', (t) => { 11 | t.deepEqual(JSON.stringify(mCJS), JSON.stringify(mESM)); 12 | 13 | const api = [ 14 | 'cache', 15 | 'config', 16 | 'data', 17 | 'runtime', 18 | 'state', 19 | 'configDirs', 20 | 'dataDirs', 21 | '$name', 22 | '$isolated', 23 | ]; 24 | 25 | t.is(typeof mCJS, 'function'); 26 | t.is(typeof mCJS, typeof mESM); 27 | t.is(Object.keys(mCJS).length, api.length); 28 | t.is(Object.keys(mCJS).length, Object.keys(mESM).length); 29 | api.forEach((key) => { 30 | /* eslint-disable @typescript-eslint/no-explicit-any , security/detect-object-injection */ 31 | t.is(typeof mCJS[key], 'function'); 32 | t.is(typeof mCJS[key], typeof (mESM as any)[key]); 33 | t.deepEqual(mCJS[key](), (mESM as any)[key]()); 34 | /* eslint-enable @typescript-eslint/no-explicit-any , security/detect-object-injection */ 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/platform-adapters/_base.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | // eslint-disable-next-line @typescript-eslint/no-namespace 3 | export namespace Platform { 4 | export type ParsedPath = { 5 | readonly base: string; 6 | readonly dir: string; 7 | readonly ext: string; 8 | readonly name: string; 9 | readonly root: string; 10 | }; 11 | export type Adapter = { 12 | readonly atImportPermissions: { 13 | /** Is general environment access granted at module import time? 14 | - note: used for graceful degradation, but this grant is *required* for unimpaired module functionality 15 | - always `true` for non-Deno platforms 16 | */ 17 | readonly env?: boolean; 18 | /** Is general file system read access granted at module import time? 19 | - note: used for graceful degradation, but this grant is *required* for unimpaired module functionality 20 | - always `true` for non-Deno platforms 21 | */ 22 | readonly read?: boolean; 23 | }; 24 | readonly meta: { 25 | readonly mainFilename: () => string | undefined; 26 | readonly pkgMainFilename: () => string | undefined; 27 | }; 28 | readonly path: { 29 | /** Path list delimiter */ 30 | readonly delimiter: string; 31 | /** @function Returns all path segments, joined using the platform-specific separator, and normalized. */ 32 | readonly join: (...paths: readonly string[]) => string; 33 | /** @function Returns the normalized path, resolving all `.` and `..` segments. */ 34 | readonly normalize: (path: string) => string; 35 | /** @function Returns an object whose properties represent significant elements of the `path`. */ 36 | readonly parse: (path: string) => ParsedPath; 37 | }; 38 | readonly process: { 39 | /** OS/platform identity string */ 40 | readonly platform: string; 41 | }; 42 | readonly xdg: { 43 | /** @function Returns the directory path for user-specific non-essential (ie, cached) data files. */ 44 | readonly cache: () => string; 45 | /** @function Returns the directory path for user-specific configuration files. */ 46 | readonly config: () => string; 47 | /** @function Returns directory path for user-specific data files. */ 48 | readonly data: () => string; 49 | /** @function Returns the directory path for user-specific non-essential runtime files (such as sockets, named pipes, etc); may be `undefined`. */ 50 | readonly runtime: () => string | undefined; 51 | /** @function Returns the directory path for user-specific state files (non-essential and more volatile than configuration files). */ 52 | readonly state: () => string; 53 | /** @function Returns a preference-ordered array of base directory paths to search for configuration files (includes `.config()` directory as first entry). */ 54 | readonly configDirs: () => readonly string[]; 55 | /** @function Returns a preference-ordered array of base directory paths to search for data files (includes `.data()` directory as first entry). */ 56 | readonly dataDirs: () => readonly string[]; 57 | }; 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /src/platform-adapters/deno.deno.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | // spell-checker:ignore Deno 3 | 4 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 5 | // @ts-ignore // deno-type URL import 6 | import * as path from 'https://deno.land/std@0.134.0/path/mod.ts'; 7 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 8 | // @ts-ignore // deno-type URL import 9 | import xdg from 'https://deno.land/x/xdg@v10.5.0/src/mod.deno.ts'; 10 | 11 | /* eslint-disable @typescript-eslint/ban-ts-comment */ 12 | 13 | // @ts-ignore // deno-type import 14 | import { Platform } from './_base.ts'; 15 | 16 | // create a local reference to refer to `Deno` (for better linting without need for multiple `// @ts-ignore` directives) 17 | // @ts-ignore // Deno alias to suppress other false-positive TS warnings 18 | const deno = Deno; 19 | 20 | // Deno general permission(s) at time of import 21 | // * Deno.Permissions (stabilized in v1.8.0) 22 | const queryEnv = await deno?.permissions?.query({ name: 'env' }); 23 | const allowEnv = (queryEnv?.state ?? 'granted') === 'granted'; 24 | const queryRead = await deno?.permissions?.query({ name: 'read' }); 25 | const allowRead = (queryRead?.state ?? 'granted') === 'granted'; 26 | 27 | export const adapter: Platform.Adapter = { 28 | atImportPermissions: { env: allowEnv, read: allowRead }, 29 | meta: { 30 | mainFilename: allowRead ? () => deno.mainModule : () => void 0, 31 | pkgMainFilename: () => void 0, 32 | }, 33 | path, 34 | process: { platform: deno.build.os }, 35 | xdg, 36 | }; 37 | 38 | /* eslint-enable @typescript-eslint/ban-ts-comment */ 39 | -------------------------------------------------------------------------------- /src/platform-adapters/node.ts: -------------------------------------------------------------------------------- 1 | // deno-fmt-ignore-file ## prefer customized `prettier` formatting 2 | 3 | import * as path from 'path'; 4 | 5 | import xdg from 'xdg-portable'; 6 | 7 | import { Platform } from './_base.js'; 8 | 9 | export const adapter: Platform.Adapter = { 10 | atImportPermissions: { env: true, read: true }, 11 | meta: { 12 | mainFilename: () => { 13 | const requireMain = 14 | typeof require !== 'undefined' && require !== null && require.main 15 | ? require.main 16 | : { filename: void 0 }; 17 | const requireMainFilename = requireMain.filename; 18 | const filename = 19 | // HACK: additional comparison `require?.main?.filename !== process.execArgv[0]` compensates for ESM scripts run via `ts-node` 20 | (requireMainFilename !== process.execArgv[0] ? requireMainFilename : void 0) || 21 | // HACK: `process._eval` is undocumented; used here (again, for ESM) as evidence of `node -e ...` differentiating between immediate eval vs file-bound scripts 22 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 23 | (typeof (process as any)._eval === 'undefined' ? process.argv[1] : void 0); 24 | return filename; 25 | }, 26 | pkgMainFilename: () => { 27 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 28 | return (process as any).pkg ? process.execPath : void 0; 29 | }, 30 | }, 31 | path, 32 | process, 33 | xdg, 34 | }; 35 | -------------------------------------------------------------------------------- /test/dist.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env es6, node */ 2 | 'use strict'; 3 | 4 | /* note: dynamic imports are used because 'dist' may not exist */ 5 | 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | const test = require('ava'); 10 | 11 | const vNodeJS = process.versions.node.split('.'); 12 | const vNodeJSMajor = +vNodeJS[0]; 13 | 14 | // Distribution tests 15 | 16 | const packagePath = '../package.json'; 17 | 18 | // eslint-disable-next-line security-node/detect-non-literal-require-calls 19 | const pkg = require(packagePath); 20 | 21 | const packageCJSPath = path.resolve(__dirname, packagePath, '..', pkg.exports['.'].require); 22 | const packageESMPath = path.resolve(__dirname, packagePath, '..', pkg.exports['.'].import); 23 | 24 | const packageAPI = [ 25 | '$name', 26 | '$isolated', 27 | 'cache', 28 | 'config', 29 | 'data', 30 | 'runtime', 31 | 'state', 32 | 'configDirs', 33 | 'dataDirs', 34 | ]; 35 | 36 | function isObject(obj) { 37 | return Object.prototype.toString.call(obj) === '[object Object]'; 38 | } 39 | 40 | function flattenToValues(obj) { 41 | const values = []; 42 | if (isObject(obj) || Array.isArray(obj)) { 43 | Object.keys(obj).forEach((key) => { 44 | // eslint-disable-next-line security/detect-object-injection 45 | values.push(...flattenToValues(obj[key])); 46 | }); 47 | } else values.push(obj); 48 | return values; 49 | } 50 | 51 | if (!process.env.npm_config_test_dist) { 52 | test.skip('skipped (enable with `npm test --test-dist`)', () => void 0); 53 | } else { 54 | const testID$CJStoESM = 'CJS/ESM equivalence'; 55 | if (vNodeJSMajor < 12) { 56 | test.skip(testID$CJStoESM + ' (requires Node-v12+)', () => void 0); 57 | } else { 58 | test(testID$CJStoESM, async (t) => { 59 | // eslint-disable-next-line security/detect-non-literal-require , security-node/detect-non-literal-require-calls 60 | const mCJS = require(packageCJSPath); 61 | const mESM = (await import('file://' + packageESMPath)).default; 62 | 63 | t.deepEqual(mCJS, mESM); 64 | 65 | t.is(typeof mCJS, 'function'); 66 | t.is(typeof mCJS, typeof mESM); 67 | t.is(Object.keys(mCJS).length, packageAPI.length); 68 | t.is(Object.keys(mCJS).length, Object.keys(mESM).length); 69 | packageAPI.forEach((key) => { 70 | /* eslint-disable security/detect-object-injection */ 71 | t.is(typeof mCJS[key], 'function'); 72 | t.is(typeof mCJS[key], typeof mESM[key]); 73 | t.deepEqual(mCJS[key](), mESM[key]()); 74 | /* eslint-enable security/detect-object-injection */ 75 | }); 76 | }); 77 | } 78 | 79 | test("package 'exports' consistency", (t) => { 80 | /* eslint-disable security/detect-non-literal-fs-filename */ 81 | t.is(pkg.main, pkg.exports['.'].require); 82 | t.is(pkg.module, pkg.exports['.'].import); 83 | t.is(pkg.types, pkg.exports['.'].types); 84 | 85 | t.true(fs.existsSync(pkg.exports['.'].require)); 86 | t.true(fs.existsSync(pkg.exports['.'].import)); 87 | t.true(fs.existsSync(pkg.exports['.'].types)); 88 | 89 | t.is(pkg.main, pkg.exports['.'].default); 90 | 91 | if (pkg.exports['./cjs']) { 92 | const pathRequire = pkg.exports['./cjs'].require; 93 | t.is(pkg.exports['.'].require, pathRequire); 94 | // const extension = path.extname(pathRequire); 95 | // const basename = path.basename(pathRequire, extension); 96 | // const dirname = path.dirname(pathRequire); 97 | // t.is(pkg.exports['./cjs'].types, path.posix.join(dirname, basename) + '.d.ts'); 98 | t.true(fs.existsSync(pkg.exports['./cjs'].require)); 99 | } 100 | 101 | // 'types' default to the Deno/ESM/TypeScript variant 102 | if (pkg.exports['./esm']) { 103 | const pathImport = pkg.exports['./esm'].import; 104 | t.is(pkg.exports['.'].import, pathImport); 105 | t.is(pkg.exports['.'].types, path.pkg.exports['./esm'].types); 106 | t.true(fs.existsSync(pkg.exports['./esm'].require)); 107 | } 108 | /* eslint-enable security/detect-non-literal-fs-filename */ 109 | }); 110 | 111 | test("package 'exports' all exist", (t) => { 112 | const exports_ = pkg.exports; 113 | const paths = flattenToValues(exports_); 114 | t.log({ exportsPaths: paths }); 115 | paths.forEach((p) => { 116 | const path_ = path.resolve(__dirname, packagePath, '..', p); 117 | // eslint-disable-next-line security/detect-non-literal-fs-filename 118 | const exists = fs.existsSync(path_); 119 | if (!exists) { 120 | t.log({ path_, exists }); 121 | } 122 | t.true(exists); 123 | }); 124 | }); 125 | 126 | test("package 'exports' sub-paths support older tools", (t) => { 127 | // confirm package files/directories exist which correspond to advertised exports sub-paths 128 | // [why]: older tools import/require based on package directory structure, not 'exports' 129 | const exports_ = pkg.exports; 130 | const subPaths = Object.keys(exports_); 131 | t.log({ subPaths }); 132 | // test for sub-path file/directory existence 133 | subPaths.forEach((p) => { 134 | const path_ = path.resolve(__dirname, packagePath, '..', p); 135 | // eslint-disable-next-line security/detect-non-literal-fs-filename 136 | const exists = fs.existsSync(path_); 137 | if (!exists) { 138 | t.log({ exists, path_ }); 139 | } 140 | t.true(exists); 141 | }); 142 | const files = pkg.files; 143 | // test that sub-path file/directory is included in 'files' 144 | subPaths.forEach((p) => { 145 | const included = p === '.' || files.includes(p.replace(/^.\//, '')); 146 | if (!included) { 147 | t.log({ included, p, files }); 148 | } 149 | t.true(included); 150 | }); 151 | }); 152 | 153 | test('package version has matching Git/VCS version tag', (t) => { 154 | t.log({ version: pkg.version }); 155 | 156 | const result = require('child_process').spawnSync('git rev-list refs/tags/v' + pkg.version, { 157 | shell: true, 158 | encoding: 'utf-8', 159 | }); 160 | t.is(result.status, 0); 161 | }); 162 | } 163 | -------------------------------------------------------------------------------- /test/fixtures/cli-display-name.cjs.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console , security-node/detect-crlf */ 2 | /* eslint-env es6, node */ 3 | 4 | const p = require('../../build/cjs/src/mod.cjs.js'); 5 | 6 | console.log(p.$name()); 7 | -------------------------------------------------------------------------------- /test/fixtures/cli-display-name.esm-wrapper.mjs: -------------------------------------------------------------------------------- 1 | /* eslint-env es6, node */ 2 | /* eslint-disable no-console , security-node/detect-crlf */ 3 | 4 | import p from '../../build/cjs/src/esm-wrapper/mod.esm.js'; 5 | 6 | console.log(p.$name()); 7 | // console.warn({ process }); 8 | -------------------------------------------------------------------------------- /test/fixtures/cli-display-name.esm.mjs: -------------------------------------------------------------------------------- 1 | /* eslint-env es6, node */ 2 | /* eslint-disable no-console , security-node/detect-crlf */ 3 | 4 | import p from '../../build/esm/src/mod.esm.js'; 5 | 6 | console.log(p.$name()); 7 | // console.warn({ process }); 8 | -------------------------------------------------------------------------------- /test/fixtures/cli-display-name.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console , security-node/detect-crlf */ 2 | 3 | // `ts-node` cannot import modules with extensions => use CJS module 4 | // ## maint: [2021-02-16; rivy] await resolution of to return to direct TS import 5 | // import p from '../../src/mod.esm.js'; 6 | import p from '../../build/cjs/src/mod.cjs.js'; 7 | 8 | console.log(p.$name()); 9 | -------------------------------------------------------------------------------- /test/fixtures/cli-display-name.umd.js: -------------------------------------------------------------------------------- 1 | /* eslint-env es6, node */ 2 | /* eslint-disable no-console , security-node/detect-crlf */ 3 | 4 | const p = require('../../build/umd/src/mod.cjs.js'); 5 | 6 | console.log(p.$name()); 7 | -------------------------------------------------------------------------------- /test/integration.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env es6, node */ 2 | /* eslint complexity: ['error', { max: 10 }] */ // set maximum cyclomatic complexity to 10; ref: 3 | /* eslint import/order: ["error", {"newlines-between": "always-and-inside-groups"}] */ 4 | 5 | // spell-checker:ignore (names) Deno ; (vars) ESM ESMs vNodeJSMajor vNodeJSminor ; (words) cyclomatic 6 | 7 | 'use strict'; 8 | 9 | const fs = require('fs'); 10 | const path = require('path'); 11 | const util = require('util'); 12 | 13 | const test = require('ava'); 14 | const commandExists = require('command-exists'); 15 | const spawn = require('cross-spawn'); 16 | 17 | const modulePath = '../build/lab/src/mod.cjs.js'; // ? change to package.main? 18 | const packagePath = '../package.json'; 19 | 20 | // eslint-disable-next-line security-node/detect-non-literal-require-calls 21 | const mod = require(modulePath); 22 | // eslint-disable-next-line security-node/detect-non-literal-require-calls 23 | const pkg = require(packagePath); 24 | 25 | const haveDeno = commandExists.sync('deno'); 26 | const denoVersion = 27 | /* `-T` (interpret as TypeScript; available v1.0+); used for older `deno` versions (< v1.16.2) which cache eval compilation incorrectly; ref: */ 28 | (( 29 | spawn.sync('deno', ['eval', '-T', '"console.log(Deno.version.deno)"'], { 30 | encoding: 'utf-8', 31 | shell: true, 32 | }).stdout || '' 33 | ).match(/(?<=^|\s)\d+(?:[.]\d+)*/ /* eslint-disable-line security/detect-unsafe-regex */) || [ 34 | '0.0.0', 35 | ])[0]; 36 | 37 | function versionCompare(a, b) { 38 | return a.localeCompare(b, /* locales */ void 0, { numeric: true }); 39 | } 40 | 41 | const vNodeJS = process.versions.node.split('.'); 42 | const vNodeJSMajor = +vNodeJS[0]; 43 | const vNodeJSminor = +vNodeJS[1]; 44 | 45 | // removal of `--experimental-modules` flag gate for ESM 46 | // ref: [NodeJS-v12.17 changes] 47 | // ref: [NodeJS-v13.2 changes] 48 | const settledSupportForESMs = 49 | vNodeJSMajor > 13 || 50 | (vNodeJSMajor === 13 && vNodeJSminor >= 2) || 51 | (vNodeJSMajor === 12 && vNodeJSminor >= 17); 52 | 53 | // Integration tests 54 | 55 | test('api', (t) => { 56 | const api = [ 57 | '$name', 58 | '$isolated', 59 | 'cache', 60 | 'config', 61 | 'data', 62 | 'runtime', 63 | 'state', 64 | 'configDirs', 65 | 'dataDirs', 66 | ]; 67 | 68 | t.is(typeof mod, 'function'); 69 | t.deepEqual(Object.keys(mod).sort(), api.sort()); 70 | api.forEach((key) => { 71 | // eslint-disable-next-line security/detect-object-injection 72 | t.is(typeof mod[key], 'function'); 73 | }); 74 | }); 75 | 76 | // ensure *no-panic* static load for Deno 77 | if (!process.env.npm_config_test_dist) { 78 | test.skip('module load test (Deno)...skipped (enable with `npm test --test-dist`)', () => void 0); 79 | } else { 80 | const minDenoVersion = '1.19.0'; 81 | if (!haveDeno) { 82 | test.skip('module load tests (Deno)...skipped (`deno` not found)', () => void 0); 83 | } else if (versionCompare(denoVersion, minDenoVersion) < 0) { 84 | test.skip(`module load tests (Deno)...skipped (using Deno v${denoVersion} [v${minDenoVersion}+ needed for use of \`--no-prompt\`])`, () => 85 | void 0); 86 | } else { 87 | test('module loads without panic (no permissions and `--no-prompt`; Deno)', (t) => { 88 | const denoModulePath = pkg.exports['.'].deno; 89 | 90 | const command = 'deno'; 91 | const args = ['run', '--no-prompt', denoModulePath]; 92 | const options = { shell: true, encoding: 'utf-8' }; 93 | 94 | const { error, status, stdout, stderr } = spawn.sync(command, args, options); 95 | 96 | if (!(error === null && status === 0)) { 97 | t.log({ denoModulePath, error, status, stdout, stderr }); 98 | } 99 | 100 | t.deepEqual({ error, status }, { error: null, status: 0 }); 101 | }); 102 | } 103 | } 104 | 105 | test('correctly derive script name (JavaScript)', (t) => { 106 | const fixtureDirPath = 'test/fixtures'; 107 | const extensions = ['.js', '.cjs', '.mjs']; 108 | 109 | const files = fs.readdirSync(fixtureDirPath); 110 | 111 | files 112 | .filter((file) => { 113 | return extensions.includes(path.extname(file)); 114 | }) 115 | .forEach((file) => { 116 | if (settledSupportForESMs || path.extname(file) === '.js') { 117 | const command = 'node'; 118 | const script = path.join(fixtureDirPath, file); 119 | const args = [script]; 120 | const options = { shell: true, encoding: 'utf-8' }; 121 | 122 | t.log({ script }); 123 | 124 | const { error, status, stdout, stderr } = spawn.sync(command, args, options); 125 | 126 | t.log({ error, status, stdout, stderr }); 127 | 128 | t.deepEqual({ error, status }, { error: null, status: 0 }); 129 | 130 | t.is(stdout.toString().trim(), path.parse(script).name); 131 | } 132 | }); 133 | }); 134 | 135 | test('correctly derive script name (TypeScript)', (t) => { 136 | const fixtureDirPath = 'test/fixtures'; 137 | const extensions = ['.js', '.cjs', '.mjs', '.ts']; 138 | 139 | const files = fs.readdirSync(fixtureDirPath); 140 | 141 | files 142 | .filter((file) => { 143 | const extension = path.extname(file); 144 | const name = path.basename(file, extension); 145 | const nameExtension = path.extname(name); 146 | const isDenoTS = extension === '.ts' && nameExtension === '.deno'; 147 | return extensions.includes(extension) && !isDenoTS; 148 | }) 149 | .forEach((file) => { 150 | if (settledSupportForESMs || path.extname(file) === '.js' || path.extname(file) === '.ts') { 151 | const command = 'node'; 152 | const script = path.join(fixtureDirPath, file); 153 | const args = ['node_modules/ts-node/dist/bin.js', script]; 154 | const options = { shell: true, encoding: 'utf8' }; 155 | 156 | t.log({ script }); 157 | 158 | const { error, status, stdout, stderr } = spawn.sync(command, args, options); 159 | 160 | t.log({ error, status, stdout, stderr }); 161 | 162 | t.deepEqual({ error, status }, { error: null, status: 0 }); 163 | 164 | t.is(stdout.toString().trim(), path.parse(script).name); 165 | } 166 | }); 167 | }); 168 | 169 | // test examples when using `--test-dist` (ie, with version changes or prior to distribution) 170 | if (!process.env.npm_config_test_dist) { 171 | test.skip('examples are executable...skipped (enable with `npm test --test-dist`)', () => void 0); 172 | } else { 173 | const minDenoVersion = '1.8.0'; 174 | if (!haveDeno) { 175 | test.skip('examples are executable (Deno)...skipped (`deno` not found)', () => void 0); 176 | } else if (versionCompare(denoVersion, minDenoVersion) < 0) { 177 | test.skip(`examples are executable (Deno)...skipped (using Deno v${denoVersion} [v${minDenoVersion}+ needed for use of stable permissions API])`, () => 178 | void 0); 179 | } else { 180 | test('examples are executable without error (Deno)', (t) => { 181 | // t.timeout(30000); // 30s timeout 182 | 183 | const egDirPath = 'eg'; 184 | const extensionRxs = [/.*[.]deno[.]ts$/i]; 185 | 186 | const files = fs.readdirSync(egDirPath); 187 | 188 | files 189 | .filter((file) => { 190 | return extensionRxs.find((re) => path.basename(file).match(re)); 191 | }) 192 | .forEach((file) => { 193 | const command = 'deno'; 194 | const script = path.join(egDirPath, file); 195 | const args = ['run', '--allow-all', script]; 196 | const options = { shell: true, encoding: 'utf-8' }; 197 | 198 | const { error, status, stdout, stderr } = spawn.sync(command, args, options); 199 | 200 | if (error === null && status === 0) { 201 | t.log( 202 | util.inspect(script, /* showHidden */ void 0, /* depth */ void 0, /* color */ true), 203 | `(exit_status=${status})` 204 | ); 205 | } else { 206 | t.log({ script, error, status, stdout, stderr }); 207 | } 208 | 209 | t.deepEqual({ error, status }, { error: null, status: 0 }); 210 | }); 211 | }); 212 | } 213 | 214 | test('examples are executable without error (JavaScript)', (t) => { 215 | // t.timeout(30000); // 30s timeout 216 | 217 | const egDirPath = 'eg'; 218 | const extensions = ['.js', '.cjs', '.mjs']; 219 | 220 | const files = fs.readdirSync(egDirPath); 221 | 222 | files 223 | .filter((file) => { 224 | return extensions.includes(path.extname(file)); 225 | }) 226 | .forEach((file) => { 227 | if (settledSupportForESMs || path.extname(file) === '.js') { 228 | const command = 'node'; 229 | const script = path.join(egDirPath, file); 230 | const args = [script]; 231 | const options = { shell: true, encoding: 'utf-8' }; 232 | 233 | const { error, status, stdout, stderr } = spawn.sync(command, args, options); 234 | 235 | if (error === null && status === 0) { 236 | t.log( 237 | util.inspect(script, /* showHidden */ void 0, /* depth */ void 0, /* color */ true), 238 | `(exit_status=${status})` 239 | ); 240 | } else { 241 | t.log({ script, error, status, stdout, stderr }); 242 | } 243 | 244 | t.deepEqual({ error, status }, { error: null, status: 0 }); 245 | } 246 | }); 247 | }); 248 | 249 | test('examples are executable without error (TypeScript)', (t) => { 250 | // t.timeout(30000); // 30s timeout 251 | 252 | const egDirPath = 'eg'; 253 | const extensions = ['.js', '.cjs', '.mjs', '.ts']; 254 | 255 | const files = fs.readdirSync(egDirPath); 256 | 257 | files 258 | .filter((file) => { 259 | const extension = path.extname(file); 260 | const name = path.basename(file, extension); 261 | const nameExtension = path.extname(name); 262 | const isDenoTS = extension === '.ts' && nameExtension === '.deno'; 263 | return extensions.includes(extension) && !isDenoTS; 264 | }) 265 | .forEach((file) => { 266 | if (settledSupportForESMs || path.extname(file) === '.js' || path.extname(file) === '.ts') { 267 | const command = 'node'; 268 | const script = path.join(egDirPath, file); 269 | const args = ['node_modules/ts-node/dist/bin.js', script]; 270 | const options = { shell: true, encoding: 'utf8' }; 271 | 272 | const { error, status, stdout, stderr } = spawn.sync(command, args, options); 273 | 274 | const basename = path.basename(file); 275 | const extension = path.extname(file); 276 | const name = path.basename(file, extension); 277 | const nameExtension = path.extname(name); 278 | 279 | if (error === null && status === 0) { 280 | t.log( 281 | util.inspect(script, /* showHidden */ void 0, /* depth */ void 0, /* color */ true), 282 | `(exit_status=${status})` 283 | ); 284 | } else { 285 | t.log({ script, basename, name, extension, nameExtension }); 286 | t.log({ script, error, status, stdout, stderr }); 287 | } 288 | 289 | t.deepEqual({ error, status }, { error: null, status: 0 }); 290 | } 291 | }); 292 | }); 293 | } 294 | -------------------------------------------------------------------------------- /test/types.test-d.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'tsd'; 2 | 3 | import xdgAppPaths from '../src/mod.esm'; 4 | 5 | expectType(xdgAppPaths); 6 | expectType(xdgAppPaths()); 7 | expectType(new xdgAppPaths()); 8 | 9 | expectType(xdgAppPaths('MyApp')); 10 | expectType(xdgAppPaths({ name: 'MyApp', suffix: '-nodejs', isolated: false })); 11 | expectType(new xdgAppPaths('MyApp')); 12 | expectType( 13 | new xdgAppPaths({ name: 'MyApp', suffix: '-nodejs', isolated: false }) 14 | ); 15 | 16 | const paths = xdgAppPaths('MyApp'); 17 | 18 | expectType(paths); 19 | 20 | expectType(paths.$name()); 21 | expectType(paths.$isolated()); 22 | 23 | expectType(paths.cache()); 24 | expectType(paths.cache(false)); 25 | expectType(paths.cache({ isolated: true })); 26 | expectType(paths.config()); 27 | expectType(paths.config(true)); 28 | expectType(paths.config({ isolated: false })); 29 | expectType(paths.data()); 30 | expectType(paths.data(false)); 31 | expectType(paths.data({ isolated: true })); 32 | expectType(paths.runtime()); 33 | expectType(paths.runtime(true)); 34 | expectType(paths.runtime({ isolated: false })); 35 | expectType(paths.state()); 36 | expectType(paths.state(false)); 37 | expectType(paths.state({ isolated: true })); 38 | expectType(paths.configDirs()); 39 | expectType(paths.configDirs(true)); 40 | expectType(paths.configDirs({ isolated: false })); 41 | expectType(paths.dataDirs()); 42 | expectType(paths.dataDirs(false)); 43 | expectType(paths.dataDirs({ isolated: true })); 44 | -------------------------------------------------------------------------------- /test/unit.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable functional/immutable-data , functional/no-loop-statement , security-node/non-literal-reg-expr , security/detect-non-literal-regexp , security/detect-object-injection */ 2 | /* eslint-env es6, node */ 3 | // spell-checker:ignore (vars) ESM ESMs vNodeJSMajor vNodeJSminor 4 | 'use strict'; 5 | 6 | const path = require('path'); 7 | 8 | const test = require('ava'); 9 | const spawn = require('cross-spawn'); 10 | 11 | const module_ = require('../build/lab/src/mod.cjs.js'); 12 | 13 | const isWinOS = /^win/i.test(process.platform); 14 | 15 | function isDefined(value) { 16 | return typeOf(value) !== 'undefined'; 17 | } 18 | 19 | function regexpEscape(s) { 20 | return s.replace(/\W/g, '\\$&'); 21 | } 22 | 23 | function typeOf(value) { 24 | return typeof value; 25 | } 26 | 27 | function xdgPathRegex(name) { 28 | return new RegExp( 29 | '(^|' + 30 | regexpEscape(path.sep) + 31 | ')' + 32 | regexpEscape(name) + 33 | '(' + 34 | // for windows, `name` may be embedded within the generated paths (instead of always trailing as in MacOS/*nix) 35 | (isWinOS ? regexpEscape(path.sep) + '|' : '') + 36 | '$)' 37 | ); 38 | } 39 | 40 | const vNodeJS = process.versions.node.split('.'); 41 | const vNodeJSMajor = +vNodeJS[0]; 42 | const vNodeJSminor = +vNodeJS[1]; 43 | 44 | // removal of `--experimental-modules` flag gate for ESM 45 | // ref: [NodeJS-v12.17 changes] 46 | // ref: [NodeJS-v13.2 changes] 47 | const settledSupportForESMs = 48 | vNodeJSMajor > 13 || 49 | (vNodeJSMajor === 13 && vNodeJSminor >= 2) || 50 | (vNodeJSMajor === 12 && vNodeJSminor >= 17); 51 | 52 | // # Unit tests 53 | 54 | test('default', (t) => { 55 | const isolated = true; 56 | const paths = module_; 57 | const regex = xdgPathRegex(paths.$name()); 58 | 59 | t.is(paths.$isolated(), isolated); 60 | 61 | Object.keys(paths).forEach((key) => { 62 | const value = paths[key]; 63 | const values = [].concat(value()); // convert value (single value or array) to a flat array 64 | t.log(key, ':', value()); 65 | values.forEach((v) => { 66 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 67 | t.regex(v, regex, `${key}:${v}`); 68 | t.deepEqual(value(), value({})); 69 | t.deepEqual(value(), value({ isolated: null })); 70 | t.deepEqual(value(), value(isolated)); 71 | t.deepEqual(value(), value({ isolated })); 72 | t.notDeepEqual(value(), value(!isolated)); 73 | t.notDeepEqual(value(), value({ isolated: !isolated })); 74 | } 75 | }); 76 | }); 77 | }); 78 | 79 | test('alternate constructor (via function())', (t) => { 80 | const isolated = true; 81 | const paths = module_(); 82 | const regex = xdgPathRegex(paths.$name()); 83 | 84 | t.is(paths.$isolated(), isolated); 85 | 86 | Object.keys(paths).forEach((key) => { 87 | const value = paths[key]; 88 | const values = [].concat(value()); // convert value (single value or array) to a flat array 89 | t.log(key, ':', value()); 90 | values.forEach((v) => { 91 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 92 | t.regex(v, regex, `${key}:${v}`); 93 | t.deepEqual(value(), value({})); 94 | t.deepEqual(value(), value({ isolated: null })); 95 | t.deepEqual(value(), value(isolated)); 96 | t.deepEqual(value(), value({ isolated })); 97 | t.notDeepEqual(value(), value(!isolated)); 98 | t.notDeepEqual(value(), value({ isolated: !isolated })); 99 | } 100 | }); 101 | }); 102 | }); 103 | 104 | test('alternate constructor (via function(...))', (t) => { 105 | const name = 'albacore'; 106 | const isolated = true; 107 | const paths = module_(name); 108 | const regex = xdgPathRegex(paths.$name()); 109 | 110 | t.is(paths.$name(), name); 111 | t.is(paths.$isolated(), isolated); 112 | 113 | Object.keys(paths).forEach((key) => { 114 | const value = paths[key]; 115 | const values = [].concat(value()); // convert value (single value or array) to a flat array 116 | t.log(key, ':', value()); 117 | values.forEach((v) => { 118 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 119 | t.regex(v, regex, `${key}:${v}`); 120 | t.deepEqual(value(), value({})); 121 | t.deepEqual(value(), value({ isolated: null })); 122 | t.deepEqual(value(), value(isolated)); 123 | t.deepEqual(value(), value({ isolated })); 124 | t.notDeepEqual(value(), value(!isolated)); 125 | t.notDeepEqual(value(), value({ isolated: !isolated })); 126 | } 127 | }); 128 | }); 129 | }); 130 | 131 | test('alternate constructor (via new())', (t) => { 132 | const isolated = true; 133 | const paths = new module_(); // aka, `new module_(undefined)` 134 | const regex = xdgPathRegex(paths.$name()); 135 | 136 | t.is(paths.$isolated(), isolated); 137 | 138 | Object.keys(paths).forEach((key) => { 139 | const value = paths[key]; 140 | const values = [].concat(value()); // convert value (single value or array) to a flat array 141 | t.log(key, ':', value()); 142 | values.forEach((v) => { 143 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 144 | t.regex(v, regex, `${key}:${v}`); 145 | t.deepEqual(value(), value({})); 146 | t.deepEqual(value(), value({ isolated: null })); 147 | t.deepEqual(value(), value(isolated)); 148 | t.deepEqual(value(), value({ isolated })); 149 | t.notDeepEqual(value(), value(!isolated)); 150 | t.notDeepEqual(value(), value({ isolated: !isolated })); 151 | } 152 | }); 153 | }); 154 | }); 155 | 156 | test('alternate constructor (via new(...))', (t) => { 157 | const isolated = true; 158 | const name = 'behemoth'; 159 | const paths = new module_(name); 160 | const regex = xdgPathRegex(paths.$name()); 161 | 162 | t.is(paths.$name(), name); 163 | t.is(paths.$isolated(), isolated); 164 | 165 | Object.keys(paths).forEach((key) => { 166 | const value = paths[key]; 167 | const values = [].concat(value()); // convert value (single value or array) to a flat array 168 | t.log(key, ':', value()); 169 | values.forEach((v) => { 170 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 171 | t.regex(v, regex, `${key}:${v}`); 172 | t.deepEqual(value(), value({})); 173 | t.deepEqual(value(), value({ isolated: null })); 174 | t.deepEqual(value(), value(isolated)); 175 | t.deepEqual(value(), value({ isolated })); 176 | t.notDeepEqual(value(), value(!isolated)); 177 | t.notDeepEqual(value(), value({ isolated: !isolated })); 178 | } 179 | }); 180 | }); 181 | }); 182 | 183 | test('construct without require.main.filename', (t) => { 184 | const isolated = true; 185 | const name = 'beholder'; 186 | 187 | const priorRequireMainFilename = require.main.filename; 188 | require.main.filename = void 0; 189 | 190 | // eslint-disable-next-line functional/no-let 191 | let paths = new module_(name); 192 | const regex = xdgPathRegex(paths.$name()); 193 | 194 | t.is(paths.$name(), name); 195 | t.is(paths.$isolated(), isolated); 196 | 197 | Object.keys(paths).forEach((key) => { 198 | const value = paths[key]; 199 | const values = [].concat(value()); // convert value (single value or array) to a flat array 200 | t.log(key, ':', value()); 201 | values.forEach((v) => { 202 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 203 | t.regex(v, regex, `${key}:${v}`); 204 | t.deepEqual(value(), value({})); 205 | t.deepEqual(value(), value({ isolated: null })); 206 | t.deepEqual(value(), value(isolated)); 207 | t.deepEqual(value(), value({ isolated })); 208 | t.notDeepEqual(value(), value(!isolated)); 209 | t.notDeepEqual(value(), value({ isolated: !isolated })); 210 | } 211 | }); 212 | }); 213 | 214 | require.main.filename = null; 215 | 216 | paths = new module_(name); 217 | 218 | t.is(paths.$name(), name); 219 | t.is(paths.$isolated(), isolated); 220 | 221 | Object.keys(paths).forEach((key) => { 222 | const value = paths[key]; 223 | const values = [].concat(value()); // convert value (single value or array) to a flat array 224 | t.log(key, ':', value()); 225 | values.forEach((v) => { 226 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 227 | t.regex(v, regex, `${key}:${v}`); 228 | t.deepEqual(value(), value(isolated)); 229 | t.deepEqual(value(), value({ isolated })); 230 | t.notDeepEqual(value(), value(!isolated)); 231 | t.notDeepEqual(value(), value({ isolated: !isolated })); 232 | } 233 | }); 234 | }); 235 | 236 | require.main.filename = priorRequireMainFilename; 237 | }); 238 | 239 | test('chosen application name', (t) => { 240 | const isolated = true; 241 | const name = 'crux'; 242 | const paths = module_(name); 243 | const regex = xdgPathRegex(name); 244 | 245 | t.is(paths.$name(), name); 246 | t.is(paths.$isolated(), isolated); 247 | 248 | Object.keys(paths).forEach((key) => { 249 | const value = paths[key]; 250 | const values = [].concat(value()); // convert value (single value or array) to a flat array 251 | t.log(key, ':', value()); 252 | values.forEach((v) => { 253 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 254 | t.regex(v, regex, `${key}:${v}`); 255 | t.deepEqual(value(), value({})); 256 | t.deepEqual(value(), value({ isolated: null })); 257 | t.deepEqual(value(), value(isolated)); 258 | t.deepEqual(value(), value({ isolated })); 259 | t.notDeepEqual(value(), value(!isolated)); 260 | t.notDeepEqual(value(), value({ isolated: !isolated })); 261 | } 262 | }); 263 | }); 264 | }); 265 | 266 | test('chosen suffix', (t) => { 267 | const isolated = true; 268 | const suffix = '-nodejs'; 269 | const paths = module_({ suffix }); 270 | const regex = xdgPathRegex(paths.$name()); 271 | 272 | t.is(paths.$isolated(), isolated); 273 | 274 | Object.keys(paths).forEach((key) => { 275 | const value = paths[key]; 276 | const values = [].concat(value()); // convert value (single value or array) to a flat array 277 | t.log(key, ':', value()); 278 | values.forEach((v) => { 279 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 280 | t.regex(v, regex, `${key}:${v}`); 281 | t.deepEqual(value(), value({})); 282 | t.deepEqual(value(), value({ isolated: null })); 283 | t.deepEqual(value(), value(isolated)); 284 | t.deepEqual(value(), value({ isolated })); 285 | t.notDeepEqual(value(), value(!isolated)); 286 | t.notDeepEqual(value(), value({ isolated: !isolated })); 287 | } 288 | }); 289 | }); 290 | }); 291 | 292 | test('chosen application name + suffix', (t) => { 293 | const isolated = true; 294 | const name = 'debacle'; 295 | const suffix = '-nodejs'; 296 | const paths = module_({ name, suffix }); 297 | const regex = xdgPathRegex(paths.$name()); 298 | 299 | t.is(paths.$name(), name + suffix); 300 | t.is(paths.$isolated(), isolated); 301 | 302 | Object.keys(paths).forEach((key) => { 303 | const value = paths[key]; 304 | const values = [].concat(value()); // convert value (single value or array) to a flat array 305 | t.log(key, ':', value()); 306 | values.forEach((v) => { 307 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 308 | t.regex(v, regex, `${key}:${v}`); 309 | t.deepEqual(value(), value({})); 310 | t.deepEqual(value(), value({ isolated: null })); 311 | t.deepEqual(value(), value(isolated)); 312 | t.deepEqual(value(), value({ isolated })); 313 | t.notDeepEqual(value(), value(!isolated)); 314 | t.notDeepEqual(value(), value({ isolated: !isolated })); 315 | } 316 | }); 317 | }); 318 | }); 319 | 320 | test('correct paths with only XDG_*_HOME set', (t) => { 321 | const envVars = { 322 | cache: 'XDG_CACHE_HOME', 323 | config: 'XDG_CONFIG_HOME', 324 | data: 'XDG_DATA_HOME', 325 | state: 'XDG_STATE_HOME', 326 | }; 327 | delete process.env.XDG_CONFIG_DIRS; 328 | delete process.env.XDG_DATA_DIRS; 329 | Object.keys(envVars).forEach((key) => { 330 | const env = envVars[key]; 331 | process.env[env] = path.join('.', env); 332 | }); 333 | 334 | const isolated = true; 335 | const name = 'excalibur'; 336 | const paths = module_(name); 337 | const regex = xdgPathRegex(paths.$name()); 338 | 339 | t.is(paths.$name(), name); 340 | t.is(paths.$isolated(), isolated); 341 | 342 | Object.keys(paths).forEach((key) => { 343 | const value = paths[key]; 344 | const values = [].concat(value()); // convert value (single value or array) to a flat array 345 | t.log(key, ':', value()); 346 | values.forEach((v) => { 347 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 348 | t.regex(v, regex, `${key}:${v}`); 349 | t.deepEqual(value(), value({})); 350 | t.deepEqual(value(), value({ isolated: null })); 351 | t.deepEqual(value(), value(isolated)); 352 | t.deepEqual(value(), value({ isolated })); 353 | t.notDeepEqual(value(), value(!isolated)); 354 | t.notDeepEqual(value(), value({ isolated: !isolated })); 355 | } 356 | }); 357 | }); 358 | 359 | Object.keys(envVars).forEach((env) => { 360 | const expectedPath = path.join(process.env[envVars[env]], name); 361 | t.is(paths[env](), expectedPath); 362 | }); 363 | 364 | const configDirs = paths.configDirs(); 365 | t.is(configDirs.length, 1); 366 | t.is(configDirs[0], paths.config()); 367 | t.deepEqual(paths.configDirs(isolated)[0], paths.config(isolated)); 368 | t.deepEqual(paths.configDirs({ isolated })[0], paths.config({ isolated })); 369 | t.deepEqual(paths.configDirs(!isolated)[0], paths.config(!isolated)); 370 | t.deepEqual(paths.configDirs({ isolated: !isolated })[0], paths.config({ isolated: !isolated })); 371 | 372 | const dataDirs = paths.dataDirs(); 373 | t.is(dataDirs.length, 1); 374 | t.is(dataDirs[0], paths.data()); 375 | t.deepEqual(paths.dataDirs(isolated)[0], paths.data(isolated)); 376 | t.deepEqual(paths.dataDirs({ isolated })[0], paths.data({ isolated })); 377 | t.deepEqual(paths.dataDirs(!isolated)[0], paths.data(!isolated)); 378 | t.deepEqual(paths.dataDirs({ isolated: !isolated })[0], paths.data({ isolated: !isolated })); 379 | }); 380 | 381 | test('correct "isolated" paths with only XDG_*_HOME set', (t) => { 382 | const envVars = { 383 | cache: 'XDG_CACHE_HOME', 384 | config: 'XDG_CONFIG_HOME', 385 | data: 'XDG_DATA_HOME', 386 | state: 'XDG_STATE_HOME', 387 | }; 388 | delete process.env.XDG_CONFIG_DIRS; 389 | delete process.env.XDG_DATA_DIRS; 390 | for (const key of Object.keys(envVars)) { 391 | const env = envVars[key]; 392 | process.env[env] = path.join('.', env); 393 | } 394 | 395 | const name = 'foundling'; 396 | const isolated = true; 397 | const paths = module_({ name, isolated }); 398 | const regex = xdgPathRegex(paths.$name()); 399 | 400 | t.is(paths.$name(), name); 401 | t.is(paths.$isolated(), isolated); 402 | 403 | Object.keys(paths).forEach((key) => { 404 | const value = paths[key]; 405 | const values = [].concat(value()); // convert value (single value or array) to a flat array 406 | t.log(key, ':', value()); 407 | values.forEach((v) => { 408 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 409 | t.regex(v, regex, `${key}:${v}`); 410 | t.deepEqual(value(), value({})); 411 | t.deepEqual(value(), value({ isolated: null })); 412 | t.deepEqual(value(), value(isolated)); 413 | t.deepEqual(value(), value({ isolated })); 414 | t.notDeepEqual(value(), value(!isolated)); 415 | t.notDeepEqual(value(), value({ isolated: !isolated })); 416 | } 417 | }); 418 | }); 419 | 420 | Object.keys(envVars).forEach((env) => { 421 | const expectedPath = path.join(process.env[envVars[env]], name); 422 | t.is(paths[env](), expectedPath); 423 | }); 424 | 425 | const configDirs = paths.configDirs(); 426 | t.is(configDirs.length, 1); 427 | t.is(configDirs[0], paths.config()); 428 | t.deepEqual(paths.configDirs(isolated)[0], paths.config(isolated)); 429 | t.deepEqual(paths.configDirs({ isolated })[0], paths.config({ isolated })); 430 | t.deepEqual(paths.configDirs(!isolated)[0], paths.config(!isolated)); 431 | t.deepEqual(paths.configDirs({ isolated: !isolated })[0], paths.config({ isolated: !isolated })); 432 | 433 | const dataDirs = paths.dataDirs(); 434 | t.is(dataDirs.length, 1); 435 | t.is(dataDirs[0], paths.data()); 436 | t.deepEqual(paths.dataDirs(isolated)[0], paths.data(isolated)); 437 | t.deepEqual(paths.dataDirs({ isolated })[0], paths.data({ isolated })); 438 | t.deepEqual(paths.dataDirs(!isolated)[0], paths.data(!isolated)); 439 | t.deepEqual(paths.dataDirs({ isolated: !isolated })[0], paths.data({ isolated: !isolated })); 440 | }); 441 | 442 | test('correct non-"isolated" paths with only XDG_*_HOME set', (t) => { 443 | const envVars = { 444 | cache: 'XDG_CACHE_HOME', 445 | config: 'XDG_CONFIG_HOME', 446 | data: 'XDG_DATA_HOME', 447 | state: 'XDG_STATE_HOME', 448 | }; 449 | delete process.env.XDG_CONFIG_DIRS; 450 | delete process.env.XDG_DATA_DIRS; 451 | Object.keys(envVars).forEach((key) => { 452 | const env = envVars[key]; 453 | process.env[env] = path.join('.', env); 454 | }); 455 | 456 | const name = 'gremlins'; 457 | const isolated = false; 458 | const paths = module_({ name, isolated }); 459 | 460 | Object.keys(paths).forEach((key) => { 461 | const value = paths[key]; 462 | t.log(key, ':', value()); 463 | }); 464 | 465 | t.is(paths.$name(), name); 466 | t.is(paths.$isolated(), isolated); 467 | 468 | Object.keys(envVars).forEach((env) => { 469 | const expectedPath = process.env[envVars[env]]; 470 | t.is(paths[env](), expectedPath); 471 | }); 472 | 473 | const configDirs = paths.configDirs(); 474 | t.is(configDirs.length, 1); 475 | t.is(configDirs[0], paths.config()); 476 | t.deepEqual(paths.configDirs(isolated)[0], paths.config(isolated)); 477 | t.deepEqual(paths.configDirs({ isolated })[0], paths.config({ isolated })); 478 | t.deepEqual(paths.configDirs(!isolated)[0], paths.config(!isolated)); 479 | t.deepEqual(paths.configDirs({ isolated: !isolated })[0], paths.config({ isolated: !isolated })); 480 | 481 | const dataDirs = paths.dataDirs(); 482 | t.is(dataDirs.length, 1); 483 | t.is(dataDirs[0], paths.data()); 484 | t.deepEqual(paths.dataDirs(isolated)[0], paths.data(isolated)); 485 | t.deepEqual(paths.dataDirs({ isolated })[0], paths.data({ isolated })); 486 | t.deepEqual(paths.dataDirs(!isolated)[0], paths.data(!isolated)); 487 | t.deepEqual(paths.dataDirs({ isolated: !isolated })[0], paths.data({ isolated: !isolated })); 488 | }); 489 | 490 | test('correct paths with XDG_* set', (t) => { 491 | const envVars = { 492 | cache: 'XDG_CACHE_HOME', 493 | config: 'XDG_CONFIG_HOME', 494 | data: 'XDG_DATA_HOME', 495 | runtime: 'XDG_RUNTIME_DIR', 496 | state: 'XDG_STATE_HOME', 497 | configDirs: 'XDG_CONFIG_DIRS', 498 | dataDirs: 'XDG_DATA_DIRS', 499 | }; 500 | Object.keys(envVars).forEach((key) => { 501 | const env = envVars[key]; 502 | process.env[env] = path.join('.', env); 503 | }); 504 | 505 | const isolated = true; 506 | const name = 'howling'; 507 | const paths = module_(name); 508 | const regex = xdgPathRegex(paths.$name()); 509 | 510 | t.is(paths.$name(), name); 511 | t.is(paths.$isolated(), isolated); 512 | 513 | Object.keys(paths).forEach((key) => { 514 | const value = paths[key]; 515 | const values = [].concat(value()); // convert value (single value or array) to a flat array 516 | t.log(key, ':', value()); 517 | values.forEach((v) => { 518 | if (!key.match(/^(\$.*)$/) && isDefined(v)) { 519 | t.regex(v, regex, `${key}:${v}`); 520 | t.deepEqual(value(), value({})); 521 | t.deepEqual(value(), value({ isolated: null })); 522 | t.deepEqual(value(), value(isolated)); 523 | t.deepEqual(value(), value({ isolated })); 524 | t.notDeepEqual(value(), value(!isolated)); 525 | t.notDeepEqual(value(), value({ isolated: !isolated })); 526 | } 527 | }); 528 | }); 529 | 530 | const configDirs = paths.configDirs(); 531 | t.is(configDirs.length, 2); 532 | t.is(configDirs[0], paths.config()); 533 | t.is(configDirs[1], path.join(envVars.configDirs, name)); 534 | t.deepEqual(paths.configDirs(isolated)[0], paths.config(isolated)); 535 | t.deepEqual(paths.configDirs({ isolated })[0], paths.config({ isolated })); 536 | t.deepEqual(paths.configDirs(!isolated)[0], paths.config(!isolated)); 537 | t.deepEqual(paths.configDirs({ isolated: !isolated })[0], paths.config({ isolated: !isolated })); 538 | t.deepEqual(paths.configDirs(isolated)[1], path.join(envVars.configDirs, name)); 539 | t.deepEqual(paths.configDirs({ isolated })[1], path.join(envVars.configDirs, name)); 540 | t.notDeepEqual(paths.configDirs(!isolated)[1], path.join(envVars.configDirs, name)); 541 | t.notDeepEqual(paths.configDirs({ isolated: !isolated })[1], path.join(envVars.configDirs, name)); 542 | 543 | const dataDirs = paths.dataDirs(); 544 | t.is(dataDirs.length, 2); 545 | t.is(dataDirs[0], paths.data()); 546 | t.is(dataDirs[1], path.join(envVars.dataDirs, name)); 547 | t.deepEqual(paths.dataDirs(isolated)[0], paths.data(isolated)); 548 | t.deepEqual(paths.dataDirs({ isolated })[0], paths.data({ isolated })); 549 | t.deepEqual(paths.dataDirs(!isolated)[0], paths.data(!isolated)); 550 | t.deepEqual(paths.dataDirs({ isolated: !isolated })[0], paths.data({ isolated: !isolated })); 551 | t.deepEqual(paths.dataDirs(isolated)[1], path.join(envVars.dataDirs, name)); 552 | t.deepEqual(paths.dataDirs({ isolated })[1], path.join(envVars.dataDirs, name)); 553 | t.notDeepEqual(paths.dataDirs(!isolated)[1], path.join(envVars.dataDirs, name)); 554 | t.notDeepEqual(paths.dataDirs({ isolated: !isolated })[1], path.join(envVars.dataDirs, name)); 555 | }); 556 | 557 | test('correct "isolated" paths with XDG_* set', (t) => { 558 | const envVars = { 559 | cache: 'XDG_CACHE_HOME', 560 | config: 'XDG_CONFIG_HOME', 561 | data: 'XDG_DATA_HOME', 562 | runtime: 'XDG_RUNTIME_DIR', 563 | state: 'XDG_STATE_HOME', 564 | configDirs: 'XDG_CONFIG_DIRS', 565 | dataDirs: 'XDG_DATA_DIRS', 566 | }; 567 | Object.keys(envVars).forEach((key) => { 568 | const env = envVars[key]; 569 | process.env[env] = path.join('.', env); 570 | }); 571 | 572 | const name = 'ignoble'; 573 | const isolated = true; 574 | const paths = module_({ name, isolated }); 575 | const regex = xdgPathRegex(paths.$name()); 576 | 577 | t.is(paths.$name(), name); 578 | t.is(paths.$isolated(), isolated); 579 | 580 | Object.keys(paths).forEach((key) => { 581 | const value = paths[key]; 582 | const values = [].concat(value()); // convert value (single value or array) to a flat array 583 | t.log(key, ':', value()); 584 | values.forEach((v) => { 585 | if (!key.match(/^(\$.*)$/) && isDefined(v)) { 586 | t.regex(v, regex, `${key}:${v}`); 587 | t.deepEqual(value(), value({})); 588 | t.deepEqual(value(), value({ isolated: null })); 589 | t.deepEqual(value(), value(isolated)); 590 | t.deepEqual(value(), value({ isolated })); 591 | t.notDeepEqual(value(), value(!isolated)); 592 | t.notDeepEqual(value(), value({ isolated: !isolated })); 593 | } 594 | }); 595 | }); 596 | 597 | const configDirs = paths.configDirs(); 598 | t.is(configDirs.length, 2); 599 | t.is(configDirs[0], paths.config()); 600 | t.is(configDirs[1], path.join(envVars.configDirs, name)); 601 | t.deepEqual(paths.configDirs(isolated)[0], paths.config(isolated)); 602 | t.deepEqual(paths.configDirs({ isolated })[0], paths.config({ isolated })); 603 | t.deepEqual(paths.configDirs(!isolated)[0], paths.config(!isolated)); 604 | t.deepEqual(paths.configDirs({ isolated: !isolated })[0], paths.config({ isolated: !isolated })); 605 | t.deepEqual(paths.configDirs(isolated)[1], path.join(envVars.configDirs, name)); 606 | t.deepEqual(paths.configDirs({ isolated })[1], path.join(envVars.configDirs, name)); 607 | t.notDeepEqual(paths.configDirs(!isolated)[1], path.join(envVars.configDirs, name)); 608 | t.notDeepEqual(paths.configDirs({ isolated: !isolated })[1], path.join(envVars.configDirs, name)); 609 | 610 | const dataDirs = paths.dataDirs(); 611 | t.is(dataDirs.length, 2); 612 | t.is(dataDirs[0], paths.data()); 613 | t.is(dataDirs[1], path.join(envVars.dataDirs, name)); 614 | t.deepEqual(paths.dataDirs(isolated)[0], paths.data(isolated)); 615 | t.deepEqual(paths.dataDirs({ isolated })[0], paths.data({ isolated })); 616 | t.deepEqual(paths.dataDirs(!isolated)[0], paths.data(!isolated)); 617 | t.deepEqual(paths.dataDirs({ isolated: !isolated })[0], paths.data({ isolated: !isolated })); 618 | t.deepEqual(paths.dataDirs(isolated)[1], path.join(envVars.dataDirs, name)); 619 | t.deepEqual(paths.dataDirs({ isolated })[1], path.join(envVars.dataDirs, name)); 620 | t.notDeepEqual(paths.dataDirs(!isolated)[1], path.join(envVars.dataDirs, name)); 621 | t.notDeepEqual(paths.dataDirs({ isolated: !isolated })[1], path.join(envVars.dataDirs, name)); 622 | }); 623 | 624 | test('correct non-"isolated" paths with XDG_* set', (t) => { 625 | const envVars = { 626 | cache: 'XDG_CACHE_HOME', 627 | config: 'XDG_CONFIG_HOME', 628 | data: 'XDG_DATA_HOME', 629 | runtime: 'XDG_RUNTIME_DIR', 630 | state: 'XDG_STATE_HOME', 631 | configDirs: 'XDG_CONFIG_DIRS', 632 | dataDirs: 'XDG_DATA_DIRS', 633 | }; 634 | Object.keys(envVars).forEach((key) => { 635 | const env = envVars[key]; 636 | process.env[env] = path.join('.', env); 637 | }); 638 | 639 | const name = 'jackals'; 640 | const isolated = false; 641 | const paths = module_({ name, isolated }); 642 | 643 | t.is(paths.$name(), name); 644 | t.is(paths.$isolated(), isolated); 645 | 646 | Object.keys(paths).forEach((key) => { 647 | const value = paths[key]; 648 | t.log(key, ':', value()); 649 | }); 650 | 651 | Object.keys(envVars).forEach((env) => { 652 | const expectedPath = process.env[envVars[env]]; 653 | if (!env.endsWith('Dirs')) { 654 | t.is(paths[env](), expectedPath); 655 | } 656 | }); 657 | 658 | const configDirs = paths.configDirs(); 659 | t.is(configDirs.length, 2); 660 | t.is(configDirs[0], paths.config()); 661 | t.is(configDirs[1], envVars.configDirs); 662 | t.deepEqual(paths.configDirs(isolated)[0], paths.config(isolated)); 663 | t.deepEqual(paths.configDirs({ isolated })[0], paths.config({ isolated })); 664 | t.deepEqual(paths.configDirs(!isolated)[0], paths.config(!isolated)); 665 | t.deepEqual(paths.configDirs({ isolated: !isolated })[0], paths.config({ isolated: !isolated })); 666 | t.deepEqual(paths.configDirs(isolated)[1], envVars.configDirs); 667 | t.deepEqual(paths.configDirs({ isolated })[1], envVars.configDirs); 668 | t.notDeepEqual(paths.configDirs(!isolated)[1], envVars.configDirs); 669 | t.notDeepEqual(paths.configDirs({ isolated: !isolated })[1], envVars.configDirs); 670 | 671 | const dataDirs = paths.dataDirs(); 672 | t.is(dataDirs.length, 2); 673 | t.is(dataDirs[0], paths.data()); 674 | t.is(dataDirs[1], envVars.dataDirs); 675 | t.deepEqual(paths.dataDirs(isolated)[0], paths.data(isolated)); 676 | t.deepEqual(paths.dataDirs({ isolated })[0], paths.data({ isolated })); 677 | t.deepEqual(paths.dataDirs(!isolated)[0], paths.data(!isolated)); 678 | t.deepEqual(paths.dataDirs({ isolated: !isolated })[0], paths.data({ isolated: !isolated })); 679 | t.deepEqual(paths.dataDirs(isolated)[1], envVars.dataDirs); 680 | t.deepEqual(paths.dataDirs({ isolated })[1], envVars.dataDirs); 681 | t.notDeepEqual(paths.dataDirs(!isolated)[1], envVars.dataDirs); 682 | t.notDeepEqual(paths.dataDirs({ isolated: !isolated })[1], envVars.dataDirs); 683 | }); 684 | 685 | test('correctly derive anonymous (CJS)', (t) => { 686 | const command = 'node'; 687 | process.env.TEST_MODULE_PATH = './build/lab/src/mod.cjs.js'; 688 | const script = 689 | '"p = require(\'' + process.env.TEST_MODULE_PATH + '\'); console.log(p.$name({}));"'; 690 | const args = ['-e', isWinOS ? script : script.replace('$name', '\\$name')]; 691 | const options = { shell: true, encoding: 'utf-8' }; 692 | 693 | t.log({ script }); 694 | 695 | const { error, status, stdout, stderr } = spawn.sync(command, args, options); 696 | 697 | t.log({ error, status, stdout, stderr }); 698 | 699 | t.deepEqual({ error, status }, { error: null, status: 0 }); 700 | 701 | t.is(stdout.toString().trim(), '$eval'); 702 | }); 703 | 704 | if (settledSupportForESMs) { 705 | test('correctly derive anonymous (ESM/[import CJS])', (t) => { 706 | const command = 'node'; 707 | process.env.TEST_MODULE_PATH = './build/lab/src/mod.cjs.js'; 708 | const script = 709 | '"import p from \'' + process.env.TEST_MODULE_PATH + '\'; console.log(p.$name({}));"'; 710 | const args = [ 711 | '--input-type=module', 712 | '-e', 713 | isWinOS ? script : script.replace('$name', '\\$name'), 714 | ]; 715 | const options = { shell: true, encoding: 'utf-8' }; 716 | 717 | t.log({ script }); 718 | 719 | const { error, status, stdout, stderr } = spawn.sync(command, args, options); 720 | 721 | t.log({ error, status, stdout, stderr }); 722 | 723 | t.deepEqual({ error, status }, { error: null, status: 0 }); 724 | 725 | t.is(stdout.toString().trim(), '$eval'); 726 | }); 727 | 728 | test('correctly derive anonymous (ESM/[esm-wrapper])', (t) => { 729 | const command = 'node'; 730 | process.env.TEST_MODULE_PATH = './build/lab/src/esm-wrapper/mod.esm.js'; 731 | const script = 732 | '"import p from \'' + process.env.TEST_MODULE_PATH + '\'; console.log(p.$name({}));"'; 733 | const args = [ 734 | '--input-type=module', 735 | '-e', 736 | isWinOS ? script : script.replace('$name', '\\$name'), 737 | ]; 738 | const options = { shell: true, encoding: 'utf-8' }; 739 | 740 | t.log({ script }); 741 | 742 | const { error, status, stdout, stderr } = spawn.sync(command, args, options); 743 | 744 | t.log({ error, status, stdout, stderr }); 745 | 746 | t.deepEqual({ error, status }, { error: null, status: 0 }); 747 | 748 | t.is(stdout.toString().trim(), '$eval'); 749 | }); 750 | 751 | test('correctly derive anonymous (ESM)', (t) => { 752 | const command = 'node'; 753 | process.env.TEST_MODULE_PATH = './build/esm/src/mod.esm.js'; 754 | const script = 755 | '"import p from \'' + process.env.TEST_MODULE_PATH + '\'; console.log(p.$name({}));"'; 756 | const args = [ 757 | '--input-type=module', 758 | '-e', 759 | isWinOS ? script : script.replace('$name', '\\$name'), 760 | ]; 761 | const options = { shell: true, encoding: 'utf-8' }; 762 | 763 | t.log({ script }); 764 | 765 | const { error, status, stdout, stderr } = spawn.sync(command, args, options); 766 | 767 | t.log({ error, status, stdout, stderr }); 768 | 769 | t.deepEqual({ error, status }, { error: null, status: 0 }); 770 | 771 | t.is(stdout.toString().trim(), '$eval'); 772 | }); 773 | } 774 | 775 | test('construct with "pkg" packaged application', (t) => { 776 | const isolated = true; 777 | 778 | const priorProcessPkg = process.pkg; 779 | process.pkg = {}; 780 | 781 | const paths = new module_(); 782 | const regex = xdgPathRegex(paths.$name()); 783 | 784 | t.is(paths.$name(), path.parse(process.execPath).name); 785 | t.is(paths.$isolated(), isolated); 786 | 787 | Object.keys(paths).forEach((key) => { 788 | const value = paths[key]; 789 | const values = [].concat(value()); // convert value (single value or array) to a flat array 790 | t.log(key, ':', value()); 791 | values.forEach((v) => { 792 | if (!key.match(/^((\$.*)|runtime)$/) && isDefined(v)) { 793 | t.regex(v, regex, `${key}:${v}`); 794 | t.deepEqual(value(), value({})); 795 | t.deepEqual(value(), value({ isolated: null })); 796 | t.deepEqual(value(), value(isolated)); 797 | t.deepEqual(value(), value({ isolated })); 798 | t.notDeepEqual(value(), value(!isolated)); 799 | t.notDeepEqual(value(), value({ isolated: !isolated })); 800 | } 801 | }); 802 | }); 803 | 804 | process.pkg = priorProcessPkg; 805 | }); 806 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "incremental": false, 4 | "target": "es3", 5 | "outDir": "build/cjs", 6 | // "rootDir": "src", // interferes with `tsd`; see ; disabling builds exactly the same files/structure except placing *.tsbuildinfo files into the respective subdirectories 7 | "moduleResolution": "node", 8 | "module": "CommonJS", 9 | "newLine": "lf", 10 | "declaration": true /* Enables automatic generation of type declarations */, 11 | "inlineSourceMap": true, 12 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 13 | "resolveJsonModule": true /* Include modules imported with .json extension.; note: UMD generation requires 'false' */, 14 | 15 | "strict": true /* Enable all strict type-checking options. */, 16 | 17 | /* Strict Type-Checking Options */ 18 | // "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, 19 | // "strictNullChecks": true /* Enable strict null checks. */, 20 | // "strictFunctionTypes": true /* Enable strict checking of function types. */, 21 | // "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */, 22 | // "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */, 23 | // "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */, 24 | 25 | /* Additional Checks */ 26 | "noUnusedLocals": true /* Report errors on unused locals. */, 27 | "noUnusedParameters": true /* Report errors on unused parameters. */, 28 | "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, 29 | "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */, 30 | 31 | /* Debugging Options */ 32 | "traceResolution": false /* Report module resolution log messages. */, 33 | "listEmittedFiles": false /* Print names of generated files part of the compilation. */, 34 | "listFiles": false /* Print names of files part of the compilation. */, 35 | "pretty": true /* Stylize errors and messages using color and context. */, 36 | 37 | /* Experimental Options */ 38 | // "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, 39 | // "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, 40 | 41 | "types": ["node"], 42 | "typeRoots": ["node_modules/@types", "src/types", "dist/types", "vendor/types"], 43 | 44 | "allowJs": true, 45 | "noEmit": true, 46 | "isolatedModules": true /* Enables warnings for code which may be interpreted incorrectly by single-file transpilation tools */, 47 | 48 | "removeComments": true 49 | }, 50 | "include": ["src/**/*", "eg/**/*", "test/**/*"], 51 | "exclude": ["src/esm-wrapper/**", "node_modules/**"], 52 | "compileOnSave": false 53 | } 54 | -------------------------------------------------------------------------------- /tsconfig/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../build/cjs", 5 | "rootDir": "..", 6 | "declaration": false, // generate side-by-side type declarations 7 | "module": "CommonJS", 8 | "noEmit": false 9 | }, 10 | "exclude": [ 11 | "../eg/**", 12 | "../src/esm-wrapper/**", 13 | "../src/**/*.deno.ts", 14 | "../src/**/*.esm.ts", 15 | "../src/**/*.spec.*", 16 | "../src/**/*.test.*", 17 | "../test/**", 18 | "../node_modules/**" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig/tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true 5 | }, 6 | "include": ["../**/*"], 7 | "exclude": ["../dist/**"] 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../build/esm", 5 | "rootDir": "..", 6 | "declaration": false, // generate side-by-side type declarations 7 | "module": "es2015", 8 | "noEmit": false 9 | }, 10 | "exclude": [ 11 | "../eg/**", 12 | "../src/esm-wrapper/**", 13 | "../src/**/*.cjs.ts", 14 | "../src/**/*.deno.ts", 15 | "../src/**/*.spec.*", 16 | "../src/**/*.test.*", 17 | "../test/**", 18 | "../node_modules/**" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig/tsconfig.lab.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../build/lab", 5 | "rootDir": "..", 6 | "declaration": true, // generate side-by-side type declarations 7 | "module": "CommonJS", 8 | "noEmit": false, 9 | "removeComments": false 10 | }, 11 | "exclude": [ 12 | "../eg/**", 13 | "../src/esm-wrapper/**", 14 | "../src/**/*.deno.ts", 15 | "../test/**/*.js", 16 | "../test/**/*.test-d.ts", 17 | "../test/fixtures/**/*", 18 | "../node_modules/**" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | // generate (only) type declaration files to 'build/types' 5 | "outDir": "../build/types", 6 | "rootDir": "..", 7 | "declaration": true, // generate type declarations 8 | "emitDeclarationOnly": true, 9 | "noEmit": false, 10 | "removeComments": false 11 | }, 12 | "exclude": [ 13 | "../eg/**", 14 | "../src/esm-wrapper/**", 15 | "../src/**/*.deno.ts", 16 | "../src/**/*.spec.*", 17 | "../src/**/*.test.*", 18 | "../test/**", 19 | "../node_modules/**" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig/tsconfig.umd.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../build/umd", 5 | "rootDir": "..", 6 | "declaration": false, // generate side-by-side type declarations 7 | "module": "UMD", 8 | "noEmit": false, 9 | "resolveJsonModule": false /* Include modules imported with .json extension.; UMD generation requires 'false' */ 10 | }, 11 | "exclude": [ 12 | "../eg/**", 13 | "../src/esm-wrapper/**", 14 | "../src/**/*.deno.ts", 15 | "../src/**/*.esm.ts", 16 | "../src/**/*.spec.*", 17 | "../src/**/*.test.*", 18 | "../test/**", 19 | "../node_modules/**" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /vendor/.gitattributes: -------------------------------------------------------------------------------- 1 | # treat third-party code/tools directory as binary by default 2 | # * note: use `git diff --text ...` to override and show differences as text 3 | * binary 4 | .gitattributes !binary 5 | --------------------------------------------------------------------------------