Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: noseglid/atom-build
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: atom-community/buildium
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Able to merge. These branches can be automatically merged.

Commits on Mar 17, 2021

  1. rename package

    idleberg committed Mar 17, 2021
    Copy the full SHA
    2edbfa5 View commit details
  2. Copy the full SHA
    d3d6428 View commit details

Commits on Mar 18, 2021

  1. remove screenshot section

    idleberg committed Mar 18, 2021
    Copy the full SHA
    7d5c63d View commit details
  2. remove getmac dependency

    idleberg committed Mar 18, 2021
    Copy the full SHA
    15fb244 View commit details
  3. remove whitespace

    idleberg committed Mar 18, 2021
    Copy the full SHA
    a38526a View commit details
  4. change repository

    idleberg committed Mar 18, 2021
    Copy the full SHA
    f762e20 View commit details
  5. update readme

    idleberg committed Mar 18, 2021
    Copy the full SHA
    113d7d6 View commit details
  6. remove ci configs

    idleberg committed Mar 18, 2021
    Copy the full SHA
    58e3b41 View commit details
  7. fix link

    idleberg committed Mar 18, 2021
    Copy the full SHA
    4e1d2f5 View commit details
  8. Prepare v0.71.0 release

    idleberg committed Mar 18, 2021
    Copy the full SHA
    d614381 View commit details
  9. fix config name

    idleberg committed Mar 18, 2021
    Copy the full SHA
    09d8ad8 View commit details
  10. Prepare v0.71.1 release

    idleberg committed Mar 18, 2021
    Copy the full SHA
    20c5bc5 View commit details
  11. add conflict warning

    idleberg committed Mar 18, 2021
    Copy the full SHA
    4be3091 View commit details
  12. convert requires to imports

    idleberg committed Mar 18, 2021
    Copy the full SHA
    0a5d31e View commit details
  13. add .babelrc

    idleberg committed Mar 18, 2021
    Copy the full SHA
    d1f3b1c View commit details
  14. add src folder

    idleberg committed Mar 18, 2021
    Copy the full SHA
    0a85cad View commit details
  15. update gitignore

    idleberg committed Mar 18, 2021
    Copy the full SHA
    7f93640 View commit details
  16. use bundler

    idleberg committed Mar 18, 2021
    Copy the full SHA
    adbb13e View commit details
  17. fix linting errors

    idleberg committed Mar 18, 2021
    Copy the full SHA
    91e5dab View commit details
  18. eslint fix && prettier

    idleberg committed Mar 18, 2021
    Copy the full SHA
    931aee8 View commit details
  19. update config

    idleberg committed Mar 18, 2021
    Copy the full SHA
    05d6e92 View commit details
  20. update config

    idleberg committed Mar 18, 2021
    Copy the full SHA
    7a2eff4 View commit details
  21. first commit

    idleberg committed Mar 18, 2021
    Copy the full SHA
    6d0340a View commit details
  22. fix rollup extension

    idleberg committed Mar 18, 2021
    Copy the full SHA
    91def20 View commit details
  23. remove lint:formatting

    idleberg committed Mar 18, 2021
    Copy the full SHA
    bd16246 View commit details
  24. add lib

    idleberg committed Mar 18, 2021
    Copy the full SHA
    7c918ec View commit details
  25. prettier

    idleberg committed Mar 18, 2021
    Copy the full SHA
    d2735c2 View commit details
  26. first commit

    idleberg committed Mar 18, 2021
    Copy the full SHA
    90eedf8 View commit details
  27. add --allow-empty flag

    idleberg committed Mar 18, 2021
    Copy the full SHA
    6896cc2 View commit details
  28. Prepare v0.72.0 release

    idleberg committed Mar 18, 2021
    Copy the full SHA
    1748b09 View commit details

Commits on Mar 19, 2021

  1. update dependencies

    idleberg committed Mar 19, 2021
    Copy the full SHA
    94c704d View commit details
  2. change heading text

    idleberg committed Mar 19, 2021
    Copy the full SHA
    d65f60a View commit details
  3. use @babel/eslint-parser

    idleberg committed Mar 19, 2021
    Copy the full SHA
    244af08 View commit details
  4. adjust printWidth

    idleberg committed Mar 19, 2021
    Copy the full SHA
    6d9ae81 View commit details
  5. rename commands

    idleberg committed Mar 19, 2021
    Copy the full SHA
    02a5cfb View commit details
  6. build

    idleberg committed Mar 19, 2021
    Copy the full SHA
    c05eec3 View commit details
  7. Copy the full SHA
    9a65cb5 View commit details
  8. yarn build

    idleberg committed Mar 19, 2021
    Copy the full SHA
    2089423 View commit details
  9. Prepare v0.73.0 release

    idleberg committed Mar 19, 2021
    Copy the full SHA
    38b226f View commit details
  10. rename commands

    idleberg committed Mar 19, 2021
    Copy the full SHA
    3143f34 View commit details
  11. Prepare v0.73.1 release

    idleberg committed Mar 19, 2021
    Copy the full SHA
    78e0f95 View commit details
  12. update readme

    idleberg committed Mar 19, 2021
    Copy the full SHA
    136056f View commit details
  13. update license

    idleberg committed Mar 19, 2021
    Copy the full SHA
    a9500fd View commit details
  14. add license

    idleberg committed Mar 19, 2021
    Copy the full SHA
    8923254 View commit details
  15. update description

    idleberg committed Mar 19, 2021
    Copy the full SHA
    b935d82 View commit details
  16. add vscode task

    idleberg committed Mar 19, 2021
    Copy the full SHA
    13e693d View commit details
  17. fix json5 detection

    idleberg committed Mar 19, 2021
    Copy the full SHA
    19cecec View commit details
  18. Prepare v0.73.2 release

    idleberg committed Mar 19, 2021
    Copy the full SHA
    064df94 View commit details
  19. update description

    idleberg committed Mar 19, 2021
    Copy the full SHA
    4cc4082 View commit details
  20. update description

    idleberg committed Mar 19, 2021
    Copy the full SHA
    89503a5 View commit details
Showing with 16,361 additions and 5,311 deletions.
  1. +12 −0 .babelrc.json
  2. +12 −0 .editorconfig
  3. +3 −0 .eslintignore
  4. +0 −7 .eslintrc
  5. +10 −0 .eslintrc.json
  6. +29 −0 .github/workflows/build.yml
  7. +22 −0 .github/workflows/stale.yml
  8. +16 −3 .gitignore
  9. +4 −0 .husky/pre-commit
  10. +2 −0 .prettierignore
  11. +16 −0 .prettierrc.json
  12. +0 −37 .travis.yml
  13. +19 −0 .vscode/tasks.json
  14. +1 −1 LICENSE.md
  15. +103 −262 README.md
  16. +0 −25 appveyor.yml
  17. +18 −18 keymaps/build.json
  18. +0 −97 lib/atom-build.js
  19. +0 −340 lib/build.js
  20. +1 −0 lib/buildium.js
  21. +0 −119 lib/config.js
  22. +0 −79 lib/google-analytics.js
  23. +0 −51 lib/linter-integration.js
  24. +0 −243 lib/target-manager.js
  25. +31 −25 menus/build.json
  26. +14,642 −0 package-lock.json
  27. +84 −29 package.json
  28. +41 −0 rollup.config.mjs
  29. +0 −5 spec/.eslintrc
  30. +0 −68 spec/build-atomCommandName-spec.js
  31. +0 −268 spec/build-confirm-spec.js
  32. +0 −720 spec/build-error-match-spec.js
  33. +0 −107 spec/build-hooks-spec.js
  34. +0 −233 spec/build-keymap-spec.js
  35. +0 −581 spec/build-spec.js
  36. +0 −223 spec/build-targets-spec.js
  37. +0 −236 spec/build-view-spec.js
  38. +0 −194 spec/build-visible-spec.js
  39. +0 −147 spec/custom-provider-spec.js
  40. +0 −6 spec/fixture/.atom-build.cson
  41. +0 −23 spec/fixture/.atom-build.error-match-function.js
  42. +0 −7 spec/fixture/.atom-build.error-match-long-output.json
  43. +0 −7 spec/fixture/.atom-build.error-match-multiple-errorMatch.json
  44. +0 −4 spec/fixture/.atom-build.error-match-multiple-first.json
  45. +0 −4 spec/fixture/.atom-build.error-match-multiple.json
  46. +0 −4 spec/fixture/.atom-build.error-match-no-exit1.json
  47. +0 −4 spec/fixture/.atom-build.error-match-no-file.json
  48. +0 −4 spec/fixture/.atom-build.error-match-no-line-col.json
  49. +0 −4 spec/fixture/.atom-build.error-match.json
  50. +0 −4 spec/fixture/.atom-build.error-match.message.json
  51. +0 −5 spec/fixture/.atom-build.js
  52. +0 −5 spec/fixture/.atom-build.json
  53. +0 −29 spec/fixture/.atom-build.match-function-change-dirs.js
  54. +0 −16 spec/fixture/.atom-build.match-function-html.js
  55. +0 −17 spec/fixture/.atom-build.match-function-message-and-html.js
  56. +0 −21 spec/fixture/.atom-build.match-function-trace-html.js
  57. +0 −22 spec/fixture/.atom-build.match-function-trace-message-and-html.js
  58. +0 −21 spec/fixture/.atom-build.match-function-trace.js
  59. +0 −16 spec/fixture/.atom-build.match-function-warning.js
  60. +0 −18 spec/fixture/.atom-build.replace.json
  61. +0 −5 spec/fixture/.atom-build.sh-default.json
  62. +0 −6 spec/fixture/.atom-build.sh-false.json
  63. +0 −6 spec/fixture/.atom-build.sh-true.json
  64. +0 −7 spec/fixture/.atom-build.shell.json
  65. +0 −3 spec/fixture/.atom-build.syntax-error.json
  66. +0 −9 spec/fixture/.atom-build.targets.json
  67. +0 −4 spec/fixture/.atom-build.warning-match.json
  68. +0 −7 spec/fixture/.atom-build.yml
  69. +0 −41 spec/fixture/atom-build-hooks-dummy-package/main.js
  70. +0 −11 spec/fixture/atom-build-hooks-dummy-package/package.json
  71. +0 −33 spec/fixture/atom-build-spec-linter/atom-build-spec-linter.js
  72. +0 −11 spec/fixture/atom-build-spec-linter/package.json
  73. +0 −9 spec/fixture/change_dir_output.txt
  74. +0 −7 spec/helpers.js
  75. +0 −349 spec/linter-intergration-spec.js
  76. +0 −85 spec/utils-spec.js
  77. +98 −0 src/atom-build.js
  78. +0 −2 {lib → src}/build-error.js
  79. +56 −47 {lib → src}/build-view.js
  80. +424 −0 src/buildium.js
  81. +183 −0 src/config.js
  82. +32 −33 {lib → src}/error-matcher.js
  83. +58 −0 src/linter-integration.js
  84. +32 −0 src/loaders.js
  85. +43 −0 src/log.js
  86. +18 −5 {lib → src}/save-confirm-view.js
  87. +6 −7 {lib → src}/status-bar-view.js
  88. +254 −0 src/target-manager.js
  89. +2 −5 {lib → src}/targets-view.js
  90. +53 −28 {lib → src}/utils.js
  91. +0 −209 styles/animations.less
  92. +34 −21 styles/build.less
  93. +1 −1 styles/panel-left-right.less
  94. +1 −1 styles/panel-top-bottom.less
12 changes: 12 additions & 0 deletions .babelrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"plugins": [],
"presets": [
[
"@babel/preset-env",
{
"corejs": "3.15",
"useBuiltIns": "entry"
}
]
]
}
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# EditorConfig is awesome: http://EditorConfig.org
root = true

[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/lib
/node_modules
/spec
7 changes: 0 additions & 7 deletions .eslintrc

This file was deleted.

10 changes: 10 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"parser": "@babel/eslint-parser",
"parserOptions": {
"sourceType": "module"
},
"rules": {
"new-cap": [2, { "capIsNewExceptions": ["XRegExp"] }],
"no-loop-func": 0
}
}
29 changes: 29 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Build & test

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: ['lts/*']

steps:
- uses: actions/checkout@v2
- name: Setting up NodeJS ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run lint --if-present
- run: npm run build --if-present
- run: npm run test --if-present
env:
CI: true
22 changes: 22 additions & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: 'Stale issues and PR'
on:
schedule:
- cron: '30 1 * * *'

jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v4
with:
stale-issue-label: stale
stale-pr-label: stale
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 14 days.'
stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 14 days.'
close-issue-message: 'This issue was closed because it has been stalled for 14 days with no activity.'
close-pr-message: 'This PR was closed because it has been stalled for 14 days with no activity.'
days-before-issue-stale: 90
days-before-pr-stale: 90
days-before-issue-close: 30
days-before-pr-close: 30
exempt-issue-labels: enhancement, bug
19 changes: 16 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
.DS_Store
npm-debug.log
/node_modules
# Package Managers
bower_components/
node_modules/
npm-debug.log*
shrinkwrap.yaml
vendor/
yarn-error.log
yarn.lock

# Development Files
.eslintcache
*.d.ts
*.map

# Project-specific
todo.md
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
lib/
node_modules/
16 changes: 16 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"arrowParens": "always",
"bracketSpacing": true,
"embeddedLanguageFormatting": "auto",
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"printWidth": 160,
"proseWrap": "preserve",
"quoteProps": "consistent",
"requirePragma": false,
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false
}
37 changes: 0 additions & 37 deletions .travis.yml

This file was deleted.

19 changes: 19 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Development",
"type": "npm",
"script": "start",
"presentation": {
"clear": true,
"focus": false,
"panel": "shared",
"showReuseMessage": true
},
"runOptions": {
"runOn": "folderOpen"
}
}
]
}
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2014 Alexander Olsson
Copyright (c) 2014-2021 Alexander Olsson, Jan T. Sott

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
365 changes: 103 additions & 262 deletions README.md

Large diffs are not rendered by default.

25 changes: 0 additions & 25 deletions appveyor.yml

This file was deleted.

36 changes: 18 additions & 18 deletions keymaps/build.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
{
".platform-darwin atom-workspace, .platform-darwin atom-text-editor": {
"cmd-alt-b": "build:trigger",
"cmd-alt-v": "build:toggle-panel",
"cmd-alt-g": "build:error-match",
"cmd-alt-h": "build:error-match-first",
"cmd-alt-t": "build:select-active-target"
"cmd-alt-b": "buildium:trigger",
"cmd-alt-v": "buildium:toggle-panel",
"cmd-alt-g": "buildium:error-match",
"cmd-alt-h": "buildium:error-match-first",
"cmd-alt-t": "buildium:select-active-target"
},
".platform-linux atom-workspace, .platform-linux atom-text-editor, .platform-win32 atom-workspace, .platform-win32 atom-text-editor": {
"ctrl-alt-b": "build:trigger",
"ctrl-alt-v": "build:toggle-panel",
"ctrl-alt-g": "build:error-match",
"ctrl-alt-h": "build:error-match-first",
"ctrl-alt-t": "build:select-active-target"
"ctrl-alt-b": "buildium:trigger",
"ctrl-alt-v": "buildium:toggle-panel",
"ctrl-alt-g": "buildium:error-match",
"ctrl-alt-h": "buildium:error-match-first",
"ctrl-alt-t": "buildium:select-active-target"
},
"atom-workspace, atom-text-editor": {
"f9": "build:trigger",
"f8": "build:toggle-panel",
"f4": "build:error-match",
"shift-f4": "build:error-match-first",
"f7": "build:select-active-target"
"f9": "buildium:trigger",
"f8": "buildium:toggle-panel",
"f4": "buildium:error-match",
"shift-f4": "buildium:error-match-first",
"f7": "buildium:select-active-target"
},
".build": {
"escape": "build:stop"
"escape": "buildium:stop"
},
".build-confirm": {
"enter": "build:confirm",
"escape": "build:no-confirm"
"enter": "buildium:confirm",
"escape": "buildium:no-confirm"
}
}
97 changes: 0 additions & 97 deletions lib/atom-build.js

This file was deleted.

340 changes: 0 additions & 340 deletions lib/build.js

This file was deleted.

1 change: 1 addition & 0 deletions lib/buildium.js

Large diffs are not rendered by default.

119 changes: 0 additions & 119 deletions lib/config.js

This file was deleted.

79 changes: 0 additions & 79 deletions lib/google-analytics.js

This file was deleted.

51 changes: 0 additions & 51 deletions lib/linter-integration.js

This file was deleted.

243 changes: 0 additions & 243 deletions lib/target-manager.js

This file was deleted.

56 changes: 31 additions & 25 deletions menus/build.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
{
"menu": [ {
"label": "Packages",
"submenu": [ {
"label": "Build",
"submenu": [ {
"label": "Build project",
"command": "build:trigger"
},
"menu": [
{
"label": "Packages",
"submenu": [
{
"label": "Terminate build",
"command": "build:stop"
},
{
"label": "Select active target",
"command": "build:select-active-target"
},
{
"label": "Refresh targets",
"command": "build:refresh-targets"
},
{
"label": "Toggle panel",
"command": "build:toggle-panel"
} ]
} ]
} ],
"label": "Buildium",
"submenu": [
{
"label": "Build project",
"command": "buildium:trigger"
},
{
"label": "Terminate build",
"command": "buildium:stop"
},
{
"label": "Select active target",
"command": "buildium:select-active-target"
},
{
"label": "Refresh targets",
"command": "buildium:refresh-targets"
},
{
"label": "Toggle panel",
"command": "buildium:toggle-panel"
}
]
}
]
}
],

"context-menu": {}
}
14,642 changes: 14,642 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

113 changes: 84 additions & 29 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,94 @@
{
"name": "build",
"main": "./lib/build",
"version": "0.70.0",
"name": "buildium",
"version": "0.75.5",
"description": "Build your current project, directly from Atom",
"repository": "https://github.com/noseglid/atom-build",
"keywords": [
"build",
"compile",
"gulp",
"make",
"productivity"
],
"repository": "https://github.com/idleberg/atom-buildium",
"license": "MIT",
"engines": {
"atom": ">=1.0.0"
"main": "./lib/buildium",
"scripts": {
"build": "npm run clean && rollup --config",
"dev": "npm run start",
"clean": "rimraf ./lib",
"format": "prettier --write ./src ./styles",
"lint:js": "eslint ./src --ignore-path .gitignore",
"lint:md": "remark . --quiet --frail --ignore-path .gitignore",
"lint": "npm-run-all --parallel lint:*",
"start": "rollup --watch --config",
"test": "eslint .",
"prepare": "husky install"
},
"lint-staged": {
"*.js": [
"eslint --cache --fix",
"prettier --write"
],
"*.{json,md,less}": "prettier --write"
},
"dependencies": {
"atom-package-deps": "^4.0.1",
"@atxm/developer-console": "^0.5.0",
"@iarna/toml": "^2.2.5",
"atom-package-deps": "^7.2.2",
"atom-space-pen-views": "^2.0.3",
"cross-spawn": "^4.0.2",
"cson-parser": "^1.3.0",
"getmac": "^1.0.7",
"js-yaml": "^3.4.6",
"term.js": "https://github.com/jeremyramin/term.js/tarball/de1635fc2695e7d8165012d3b1d007d7ce60eea2",
"core-js": "^3.15.2",
"cosmiconfig": "^7.0.0",
"cross-spawn": "^7.0.3",
"cson-parser": "^4.0.8",
"js-yaml": "^4.0.0",
"json5": "^2.2.0",
"tree-kill": "^1.0.0",
"xregexp": "^3.1.0"
"xregexp": "^5.0.1",
"xterm": "^2.9.2"
},
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/eslint-parser": "^7.14.7",
"@babel/preset-env": "^7.14.7",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^19.0.1",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.2",
"@stylelint/prettier-config": "^2.0.0",
"@stylelint/remark-preset": "^2.0.0",
"atom-build-spec-helpers": "^0.4.0",
"babel-eslint": "^6.0.0",
"eslint": "^2.10.1",
"eslint-config-atom-build": "^3.0.0",
"fs-extra": "^2.1.2",
"temp": "^0.8.1"
"eslint": "^7.31.0",
"husky": "^7.0.0",
"jsonlint": "^1.6.3",
"lint-staged": "^11.0.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.3.2",
"remark-cli": "^9.0.0",
"rimraf": "^3.0.2",
"rollup": "^2.53.2",
"rollup-plugin-terser": "^7.0.2",
"sass": "^1.35.2",
"stylelint": "^13.13.1",
"temp": "^0.9.4"
},
"package-deps": [
"busy-signal"
"engines": {
"atom": ">=1.0.0"
},
"activationCommands": {
"atom-workspace": [
"build:confirm",
"build:error-match-first",
"build:error-match",
"build:no-confirm",
"build:refresh-targets",
"build:select-active-target",
"build:stop",
"build:toggle-panel",
"build:trigger"
]
},
"activationHooks": [
"core:loaded-shell-environment"
],
"consumedServices": {
"builder": {
@@ -52,14 +112,9 @@
}
}
},
"scripts": {
"test": "eslint ."
},
"keywords": [
"build",
"compile",
"gulp",
"make",
"productivity"
"package-deps": [
{
"name": "busy-signal"
}
]
}
41 changes: 41 additions & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { babel } from '@rollup/plugin-babel';
import { terser } from "rollup-plugin-terser";
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';

const plugins = [
babel({
babelHelpers: 'bundled'
}),
commonjs(),
json(),
(
process.env.ROLLUP_WATCH
? undefined
: terser()
)
];

export default [
{
input: 'src/buildium.js',
output: {
dir: 'lib',
exports: 'default',
format: 'cjs',
sourcemap: process.env.ROLLUP_WATCH ? true : false
},
external: [
// Atom
'atom',
'electron',

// Node
'child_process',
'fs',
'os',
'path'
],
plugins: plugins
}
];
5 changes: 0 additions & 5 deletions spec/.eslintrc

This file was deleted.

68 changes: 0 additions & 68 deletions spec/build-atomCommandName-spec.js

This file was deleted.

268 changes: 0 additions & 268 deletions spec/build-confirm-spec.js

This file was deleted.

720 changes: 0 additions & 720 deletions spec/build-error-match-spec.js

This file was deleted.

107 changes: 0 additions & 107 deletions spec/build-hooks-spec.js

This file was deleted.

233 changes: 0 additions & 233 deletions spec/build-keymap-spec.js

This file was deleted.

581 changes: 0 additions & 581 deletions spec/build-spec.js

This file was deleted.

223 changes: 0 additions & 223 deletions spec/build-targets-spec.js

This file was deleted.

236 changes: 0 additions & 236 deletions spec/build-view-spec.js

This file was deleted.

194 changes: 0 additions & 194 deletions spec/build-visible-spec.js

This file was deleted.

147 changes: 0 additions & 147 deletions spec/custom-provider-spec.js

This file was deleted.

6 changes: 0 additions & 6 deletions spec/fixture/.atom-build.cson

This file was deleted.

23 changes: 0 additions & 23 deletions spec/fixture/.atom-build.error-match-function.js

This file was deleted.

7 changes: 0 additions & 7 deletions spec/fixture/.atom-build.error-match-long-output.json

This file was deleted.

7 changes: 0 additions & 7 deletions spec/fixture/.atom-build.error-match-multiple-errorMatch.json

This file was deleted.

4 changes: 0 additions & 4 deletions spec/fixture/.atom-build.error-match-multiple-first.json

This file was deleted.

4 changes: 0 additions & 4 deletions spec/fixture/.atom-build.error-match-multiple.json

This file was deleted.

4 changes: 0 additions & 4 deletions spec/fixture/.atom-build.error-match-no-exit1.json

This file was deleted.

4 changes: 0 additions & 4 deletions spec/fixture/.atom-build.error-match-no-file.json

This file was deleted.

4 changes: 0 additions & 4 deletions spec/fixture/.atom-build.error-match-no-line-col.json

This file was deleted.

4 changes: 0 additions & 4 deletions spec/fixture/.atom-build.error-match.json

This file was deleted.

4 changes: 0 additions & 4 deletions spec/fixture/.atom-build.error-match.message.json

This file was deleted.

5 changes: 0 additions & 5 deletions spec/fixture/.atom-build.js

This file was deleted.

5 changes: 0 additions & 5 deletions spec/fixture/.atom-build.json

This file was deleted.

29 changes: 0 additions & 29 deletions spec/fixture/.atom-build.match-function-change-dirs.js

This file was deleted.

16 changes: 0 additions & 16 deletions spec/fixture/.atom-build.match-function-html.js

This file was deleted.

17 changes: 0 additions & 17 deletions spec/fixture/.atom-build.match-function-message-and-html.js

This file was deleted.

21 changes: 0 additions & 21 deletions spec/fixture/.atom-build.match-function-trace-html.js

This file was deleted.

22 changes: 0 additions & 22 deletions spec/fixture/.atom-build.match-function-trace-message-and-html.js

This file was deleted.

21 changes: 0 additions & 21 deletions spec/fixture/.atom-build.match-function-trace.js

This file was deleted.

16 changes: 0 additions & 16 deletions spec/fixture/.atom-build.match-function-warning.js

This file was deleted.

18 changes: 0 additions & 18 deletions spec/fixture/.atom-build.replace.json

This file was deleted.

5 changes: 0 additions & 5 deletions spec/fixture/.atom-build.sh-default.json

This file was deleted.

6 changes: 0 additions & 6 deletions spec/fixture/.atom-build.sh-false.json

This file was deleted.

6 changes: 0 additions & 6 deletions spec/fixture/.atom-build.sh-true.json

This file was deleted.

7 changes: 0 additions & 7 deletions spec/fixture/.atom-build.shell.json

This file was deleted.

3 changes: 0 additions & 3 deletions spec/fixture/.atom-build.syntax-error.json

This file was deleted.

9 changes: 0 additions & 9 deletions spec/fixture/.atom-build.targets.json

This file was deleted.

4 changes: 0 additions & 4 deletions spec/fixture/.atom-build.warning-match.json

This file was deleted.

7 changes: 0 additions & 7 deletions spec/fixture/.atom-build.yml

This file was deleted.

41 changes: 0 additions & 41 deletions spec/fixture/atom-build-hooks-dummy-package/main.js

This file was deleted.

11 changes: 0 additions & 11 deletions spec/fixture/atom-build-hooks-dummy-package/package.json

This file was deleted.

33 changes: 0 additions & 33 deletions spec/fixture/atom-build-spec-linter/atom-build-spec-linter.js

This file was deleted.

11 changes: 0 additions & 11 deletions spec/fixture/atom-build-spec-linter/package.json

This file was deleted.

9 changes: 0 additions & 9 deletions spec/fixture/change_dir_output.txt

This file was deleted.

7 changes: 0 additions & 7 deletions spec/helpers.js

This file was deleted.

349 changes: 0 additions & 349 deletions spec/linter-intergration-spec.js

This file was deleted.

85 changes: 0 additions & 85 deletions spec/utils-spec.js

This file was deleted.

98 changes: 98 additions & 0 deletions src/atom-build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { cosmiconfig, defaultLoaders } from 'cosmiconfig';
import EventEmitter from 'events';
import fs from 'fs';
import loaders from './loaders';
import os from 'os';
import path from 'path';
import pkg from '../package.json';

const explorer = cosmiconfig(pkg.name, {
searchPlaces: ['.atom-build.cjs', '.atom-build.js', '.atom-build.json', '.atom-build.json5', '.atom-build.toml', '.atom-build.yaml', '.atom-build.yml'],
loaders: {
'.cson': loaders.cson,
'.toml': loaders.toml,
'.json': loaders.json5,
'.json5': loaders.json5,
'noExt': defaultLoaders['.json']
}
});

async function getConfig(file) {
const realFile = await fs.promises.realpath(file);

return (await explorer.load(realFile)).config || {};
}

function createBuildConfig(build, name) {
const conf = {
name: 'Custom: ' + name,
exec: build.cmd,
env: build.env,
args: build.args,
cwd: build.cwd,
sh: build.sh,
errorMatch: build.errorMatch,
functionMatch: build.functionMatch,
warningMatch: build.warningMatch,
atomCommandName: build.atomCommandName,
keymap: build.keymap,
killSignals: build.killSignals
};

if (typeof build.postBuild === 'function') {
conf.postBuild = build.postBuild;
}

if (typeof build.preBuild === 'function') {
conf.preBuild = build.preBuild;
}

return conf;
}

export default class CustomFile extends EventEmitter {
constructor(cwd) {
super();
this.cwd = cwd;
this.fileWatchers = [];
}

destructor() {
this.fileWatchers.map((fw) => fw.close());
}

getNiceName() {
return 'Custom file';
}

isEligible() {
this.files = [].concat
.apply(
[],
['cjs', 'js', 'json', 'json5', 'cson', , 'toml', 'yaml', 'yml'].map((ext) => [
path.join(this.cwd, `.atom-build.${ext}`),
path.join(os.homedir(), `.atom-build.${ext}`)
])
)
.filter(fs.existsSync);
return 0 < this.files.length;
}

async settings() {
this.fileWatchers.map((fw) => fw.close());
// On Linux, closing a watcher triggers a new callback, which causes an infinite loop
// fallback to `watchFile` here which polls instead.
this.fileWatchers = this.files.map((file) => (os.platform() === 'linux' ? fs.watchFile : fs.watch)(file, () => this.emit('refresh')));

const config = [];
const buildConfigs = await Promise.all(this.files.map(async (file) => await getConfig(file)));
buildConfigs.map((build) => {
config.push(
createBuildConfig(build, build.name || 'default'),
...Object.keys(build.targets || {}).map((name) => createBuildConfig(build.targets[name], name))
);
});

return config;
}
}
2 changes: 0 additions & 2 deletions lib/build-error.js → src/build-error.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use babel';

export default class BuildError extends Error {
constructor(name, message) {
super(message);
103 changes: 56 additions & 47 deletions lib/build-view.js → src/build-view.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,50 @@
'use babel';

import { capitalizedName, getVersion } from './utils';
import { View, $ } from 'atom-space-pen-views';
import Config from './config';
import Terminal from 'xterm';

export default class BuildView extends View {

static initialTimerText() {
return '0.0 s';
return '0.000 s';
}

static initialHeadingText() {
return 'Atom Build';
return `${capitalizedName()} ${getVersion()}`;
}

static content() {
this.div({ tabIndex: -1, class: 'build tool-panel native-key-bindings' }, () => {
this.div({ class: 'heading', outlet: 'panelHeading' }, () => {
this.div({ class: 'control-container opaque-hover' }, () => {
this.button({ class: 'btn btn-default icon icon-zap', click: 'build', title: 'Build current project' });
this.button({ class: 'btn btn-default icon icon-trashcan', click: 'clearOutput' });
this.button({ class: 'btn btn-default icon icon-x', click: 'close' });
this.div({ class: 'control-container' }, () => {
this.button(
{
class: 'btn btn-default icon icon-zap',
click: 'build',
title: 'Builds current project'
},
'Build'
);
this.button(
{
class: 'btn btn-default icon icon-trashcan',
click: 'clearOutput',
title: 'Clears the output'
},
'Clear'
);
this.button(
{
class: 'btn btn-default icon icon-x',
click: 'close',
title: 'Closes the build panel'
},
'Close'
);
this.div({ class: 'title', outlet: 'title' }, () => {
this.span({ class: 'build-timer', outlet: 'buildTimer' }, this.initialTimerText());
});
});
this.div({ class: 'icon heading-text', outlet: 'heading' }, this.initialHeadingText());
this.div({ class: 'icon heading-text text-highlight', outlet: 'heading' }, this.initialHeadingText());
});

this.div({ class: 'output panel-body', outlet: 'output' });
@@ -33,19 +54,18 @@ export default class BuildView extends View {

constructor(...args) {
super(...args);
const Terminal = require('term.js');
this.starttime = new Date();
this.terminal = new Terminal({
cursorBlink: false,
convertEol: true,
useFocus: false,
termName: 'xterm-256color',
scrollback: atom.config.get('build.terminalScrollback')
scrollback: Config.get('terminalScrollback')
});

// On some systems, prependListern and prependOnceListener is expected to exist. Add them until terminal replacement is here.
this.terminal.prependListener = (...a) => {
this.terminal.addListener(...a);
this.terminal.on(...a);
};
this.terminal.prependOnceListener = (...a) => {
this.terminal.addOnceListener(...a);
@@ -59,27 +79,20 @@ export default class BuildView extends View {

this.fontGeometry = { w: 15, h: 15 };
this.terminal.open(this.output[0]);
this.destroyTerminal = ::(this.terminal).destroy;
this.destroyTerminal = this.terminal.destroy.bind(this);
this.terminal.destroy = this.terminal.destroySoon = () => {}; // This terminal will be open forever and reset when necessary
this.terminalEl = $(this.terminal.element);
this.terminalEl[0].terminal = this.terminal; // For testing purposes

this.resizeStarted = ::this.resizeStarted;
this.resizeMoved = ::this.resizeMoved;
this.resizeEnded = ::this.resizeEnded;
this.resizeStarted = this.resizeStarted.bind(this);
this.resizeMoved = this.resizeMoved.bind(this);
this.resizeEnded = this.resizeEnded.bind(this);

atom.config.observe('build.panelVisibility', ::this.visibleFromConfig);
atom.config.observe('build.panelOrientation', ::this.orientationFromConfig);
atom.config.observe('build.hidePanelHeading', (hide) => {
hide && this.panelHeading.hide() || this.panelHeading.show();
});
atom.config.observe('build.overrideThemeColors', (override) => {
this.output.removeClass('override-theme');
override && this.output.addClass('override-theme');
});
atom.config.observe('editor.fontSize', ::this.fontSizeFromConfig);
atom.config.observe('editor.fontFamily', ::this.fontFamilyFromConfig);
atom.commands.add('atom-workspace', 'build:toggle-panel', ::this.toggle);
Config.observe('panelVisibility', this.visibleFromConfig.bind(this));
Config.observe('panelOrientation', this.orientationFromConfig.bind(this));
atom.config.observe('editor.fontSize', this.fontSizeFromConfig.bind(this));
atom.config.observe('editor.fontFamily', this.fontFamilyFromConfig.bind(this));
atom.commands.add('atom-workspace', 'buildium:toggle-panel', this.toggle.bind(this));
}

destroy() {
@@ -96,10 +109,10 @@ export default class BuildView extends View {
resizeMoved(ev) {
const { h } = this.fontGeometry;

switch (atom.config.get('build.panelOrientation')) {
switch (Config.get('panelOrientation')) {
case 'Bottom': {
const delta = this.resizer.get(0).getBoundingClientRect().top - ev.y;
if (Math.abs(delta) < (h * 5 / 6)) return;
if (Math.abs(delta) < (h * 5) / 6) return;

const nearestRowHeight = Math.round((this.terminalEl.height() + delta) / h) * h;
const maxHeight = $('.item-views').height() + $('.build .output').height();
@@ -109,7 +122,7 @@ export default class BuildView extends View {

case 'Top': {
const delta = this.resizer.get(0).getBoundingClientRect().top - ev.y;
if (Math.abs(delta) < (h * 5 / 6)) return;
if (Math.abs(delta) < (h * 5) / 6) return;

const nearestRowHeight = Math.round((this.terminalEl.height() - delta) / h) * h;
const maxHeight = $('.item-views').height() + $('.build .output').height();
@@ -140,17 +153,14 @@ export default class BuildView extends View {
}

resizeToNearestRow() {
if (-1 !== [ 'Top', 'Bottom' ].indexOf(atom.config.get('build.panelOrientation'))) {
if (-1 !== ['Top', 'Bottom'].indexOf(Config.get('panelOrientation'))) {
this.fixTerminalElHeight();
}
this.resizeTerminal();
}

getFontGeometry() {
const o = $('<div>A</div>')
.addClass('terminal')
.addClass('terminal-test')
.appendTo(this.output);
const o = $('<div>A</div>').addClass('terminal').addClass('terminal-test').appendTo(this.output);
const w = o[0].getBoundingClientRect().width;
const h = o[0].getBoundingClientRect().height;
o.remove();
@@ -164,8 +174,8 @@ export default class BuildView extends View {
return;
}

const terminalWidth = Math.floor((this.terminalEl.width()) / w);
const terminalHeight = Math.floor((this.terminalEl.height()) / h);
const terminalWidth = Math.floor(this.terminalEl.width() / w);
const terminalHeight = Math.floor(this.terminalEl.height() / h);

this.terminal.resize(terminalWidth, terminalHeight);
}
@@ -176,7 +186,7 @@ export default class BuildView extends View {

attach(force = false) {
if (!force) {
switch (atom.config.get('build.panelVisibility')) {
switch (Config.get('panelVisibility')) {
case 'Hidden':
case 'Show on Error':
return;
@@ -193,7 +203,7 @@ export default class BuildView extends View {
Left: atom.workspace.addLeftPanel,
Right: atom.workspace.addRightPanel
};
const orientation = atom.config.get('build.panelOrientation') || 'Bottom';
const orientation = Config.get('panelOrientation') || 'Bottom';
this.panel = addfn[orientation].call(atom.workspace, { item: this });
this.fixTerminalElHeight();
this.resizeToNearestRow();
@@ -209,7 +219,7 @@ export default class BuildView extends View {
if (atom.views.getView(atom.workspace) && document.activeElement === this[0]) {
atom.views.getView(atom.workspace).focus();
}
if (this.panel && (force || 'Keep Visible' !== atom.config.get('build.panelVisibility'))) {
if (this.panel && (force || 'Keep Visible' !== Config.get('panelVisibility'))) {
this.panel.destroy();
this.panel = null;
}
@@ -281,7 +291,7 @@ export default class BuildView extends View {
}

updateTitle() {
this.buildTimer.text(((new Date() - this.starttime) / 1000).toFixed(1) + ' s');
this.buildTimer.text(((new Date() - this.starttime) / 1000).toFixed(3) + ' s');
this.titleTimer = setTimeout(this.updateTitle.bind(this), 100);
}

@@ -290,7 +300,6 @@ export default class BuildView extends View {
}

toggle() {
require('./google-analytics').sendEvent('view', 'panel toggled');
this.isAttached() ? this.detach(true) : this.attach(true);
}

@@ -299,7 +308,7 @@ export default class BuildView extends View {
}

build() {
atom.commands.dispatch(atom.views.getView(atom.workspace), 'build:trigger');
atom.commands.dispatch(atom.views.getView(atom.workspace), 'buildium:trigger');
}

setHeading(heading) {
@@ -310,15 +319,15 @@ export default class BuildView extends View {
this.starttime = new Date();
this.reset();
this.attach();
if (atom.config.get('build.stealFocus')) {
if (Config.get('stealFocus')) {
this.focus();
}
this.updateTitle();
}

buildFinished(success) {
if (!success && !this.isAttached()) {
this.attach(atom.config.get('build.panelVisibility') === 'Show on Error');
this.attach(Config.get('panelVisibility') === 'Show on Error');
}
this.finalizeBuild(success);
}
424 changes: 424 additions & 0 deletions src/buildium.js

Large diffs are not rendered by default.

183 changes: 183 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { name } from '../package.json';

export default {
schema: {
panelVisibility: {
title: 'Panel Visibility',
description: 'Set when the build panel should be visible.',
type: 'string',
default: 'Toggle',
enum: ['Toggle', 'Keep Visible', 'Show on Error', 'Hidden'],
order: 1
},
autoToggleInterval: {
title: 'Auto-toggle Interval',
description: 'Set the interval until the panel closes automatically, in milliseconds. This setting works with *Panel Visibility* set to *Toggle*',
type: 'integer',
minimum: 1000,
default: 3000,
order: 2
},
buildOnSave: {
title: 'Automatically build on save',
description: 'Automatically build your project each time an editor is saved.',
type: 'boolean',
default: false,
order: 3
},
saveOnBuild: {
title: 'Automatically save on build',
description: 'Automatically save all edited files when triggering a build.',
type: 'boolean',
default: false,
order: 4
},
matchedErrorFailsBuild: {
title: 'Any matched error will fail the build',
description: 'Even if the build has a return code of zero it is marked as "failed" if any error is being matched in the output.',
type: 'boolean',
default: true,
order: 5
},
scrollOnError: {
title: 'Automatically scroll on build error',
description: 'Automatically scroll to first matched error when a build failed.',
type: 'boolean',
default: false,
order: 6
},
stealFocus: {
title: 'Steal Focus',
description: 'Steal focus when opening build panel.',
type: 'boolean',
default: true,
order: 7
},
selectTriggers: {
title: 'Selecting new target triggers the build',
description: 'When selecting a new target (through status-bar, cmd-alt-t, etc), the newly selected target will be triggered.',
type: 'boolean',
default: true,
order: 9
},
refreshOnShowTargetList: {
title: 'Refresh targets when the target list is shown',
description: 'When opening the targets menu, the targets will be refreshed.',
type: 'boolean',
default: false,
order: 10
},
notificationOnRefresh: {
title: 'Show notification when targets are refreshed',
description: 'When targets are refreshed a notification with information about the number of targets will be displayed.',
type: 'boolean',
default: false,
order: 11
},
beepWhenDone: {
title: 'Beep when the build completes',
description: 'Make a "beep" notification sound when the build is complete - in success or failure.',
type: 'boolean',
default: false,
order: 12
},
panelOrientation: {
title: 'Panel Orientation',
description: 'Where to attach the build panel',
type: 'string',
default: 'Bottom',
enum: ['Bottom', 'Top', 'Left', 'Right'],
order: 13
},
statusBar: {
title: 'Status Bar',
description: 'Where to place the status bar. Set to `Disable` to disable status bar display.',
type: 'string',
default: 'Left',
enum: ['Left', 'Right', 'Disable'],
order: 14
},
statusBarPriority: {
title: 'Priority on Status Bar',
description: 'Lower priority tiles are placed further to the left/right, depends on where you choose to place Status Bar.',
type: 'integer',
default: -1000,
order: 15
},
terminalScrollback: {
title: 'Terminal Scrollback Size',
description: 'Max number of lines of build log kept in the terminal',
type: 'integer',
default: 1000,
order: 16
},
muteConflictWarning: {
title: 'Mute Conflict Warning',
description: 'Disables the startup dialog, whether the user wants to disable the original `build` package',
type: 'boolean',
default: false,
order: 17
}
},

get(key = '') {
return key?.length ? atom.config.get(`${name}.${key}`) : atom.config.get(`${name}`);
},

set(key, value) {
atom.config.set(`${name}.${key}`, value);
},

migrate(oldKey, newKey) {
if (!atom.config.get(`${name}.${oldKey}`) || atom.config.get(`${name}.${newKey}`)) {
return;
}

try {
atom.config.set(`${name}.${newKey}`, atom.config.get(`${name}.${oldKey}`));
} catch (error) {
atom.notifications.addWarning(`Failed to migrate configuration, see console for details`);

return;
}

atom.config.unset(`${name}.${oldKey}`);
},

observe(...args) {
let key, options, callback;

switch (args.length) {
case 2:
[key, callback] = args;
options = {};
break;

case 3:
[keyPath, options, callback] = args;
break;

default:
console.error('An unsupported form of Config::observe is being used. See https://atom.io/docs/api/latest/Config for details');
return;
}

atom.config.observe(`${name}.${key}`, options, callback);
},

unset(key = '') {
const unsetKey = key?.length ? `${name}.${key}` : name;

atom.config.unset(unsetKey);
},

open(options = {}) {
options = {
pending: true,
searchAllPanes: true,
...options
};

atom.workspace.open(`atom://config/packages/${name}`, options);
}
};
65 changes: 32 additions & 33 deletions lib/error-matcher.js → src/error-matcher.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use babel';

import { EventEmitter } from 'events';
import fs from 'fs';
import path from 'path';
import XRegExp from 'xregexp';

export default class ErrorMatcher extends EventEmitter {

constructor() {
super();
this.regex = null;
@@ -13,8 +13,8 @@ export default class ErrorMatcher extends EventEmitter {
this.currentMatch = [];
this.firstMatchId = null;

atom.commands.add('atom-workspace', 'build:error-match', ::this.match);
atom.commands.add('atom-workspace', 'build:error-match-first', ::this.matchFirst);
atom.commands.add('atom-workspace', 'buildium:error-match', this.match.bind(this));
atom.commands.add('atom-workspace', 'buildium:error-match-first', this.matchFirst.bind(this));
}

_gotoNext() {
@@ -26,9 +26,9 @@ export default class ErrorMatcher extends EventEmitter {
}

goto(id) {
const match = this.currentMatch.find(m => m.id === id);
const match = this.currentMatch.find((m) => m.id === id);
if (!match) {
this.emit('error', 'Can\'t find match with id ' + id);
this.emit('error', "Can't find match with id " + id);
return;
}

@@ -40,19 +40,18 @@ export default class ErrorMatcher extends EventEmitter {

let file = match.file;
if (!file) {
this.emit('error', 'Did not match any file. Don\'t know what to open.');
this.emit('error', "Did not match any file. Don't know what to open.");
return;
}

const path = require('path');
if (!path.isAbsolute(file)) {
file = this.cwd + path.sep + file;
}

const row = match.line ? match.line - 1 : 0; /* Because atom is zero-based */
const col = match.col ? match.col - 1 : 0; /* Because atom is zero-based */

require('fs').exists(file, (exists) => {
fs.exists(file, (exists) => {
if (!exists) {
this.emit('error', 'Matched file does not exist: ' + file);
return;
@@ -70,37 +69,41 @@ export default class ErrorMatcher extends EventEmitter {
this.currentMatch = [];

// first run all functional matches
this.functions && this.functions.forEach((f, functionIndex) => {
this.currentMatch = this.currentMatch.concat(f(this.output).map((match, matchIndex) => {
match.id = 'error-match-function-' + functionIndex + '-' + matchIndex;
match.type = match.type || 'Error';
return match;
}));
});
this.functions &&
this.functions.forEach((f, functionIndex) => {
this.currentMatch = this.currentMatch.concat(
f(this.output).map((match, matchIndex) => {
match.id = 'error-match-function-' + functionIndex + '-' + matchIndex;
match.type = match.type || 'Error';
return match;
})
);
});
// then for all match kinds
Object.keys(this.regex).forEach(kind => {
Object.keys(this.regex).forEach((kind) => {
// run all matches
this.regex[kind] && this.regex[kind].forEach((regex, i) => {
regex && require('xregexp').forEach(this.output, regex, (match, matchIndex) => {
match.id = 'error-match-' + i + '-' + matchIndex;
match.type = kind;
this.currentMatch.push(match);
this.regex[kind] &&
this.regex[kind].forEach((regex, i) => {
regex &&
XRegExp.forEach(this.output, regex, (match, matchIndex) => {
match.id = 'error-match-' + i + '-' + matchIndex;
match.type = kind;
this.currentMatch.push(match);
});
});
});
});

this.currentMatch.sort((a, b) => a.index - b.index);

this.firstMatchId = (this.currentMatch.length > 0) ? this.currentMatch[0].id : null;
this.firstMatchId = this.currentMatch.length > 0 ? this.currentMatch[0].id : null;
}

_prepareRegex(regex) {
regex = regex || [];
regex = (regex instanceof Array) ? regex : [ regex ];
regex = regex instanceof Array ? regex : [regex];

return regex.map(r => {
return regex.map((r) => {
try {
const XRegExp = require('xregexp');
return XRegExp(r);
} catch (err) {
this.emit('error', 'Error parsing regex. ' + err.message);
@@ -111,7 +114,7 @@ export default class ErrorMatcher extends EventEmitter {

set(target, cwd, output) {
if (target.functionMatch) {
this.functions = ((target.functionMatch instanceof Array) ? target.functionMatch : [ target.functionMatch ]).filter(f => {
this.functions = (target.functionMatch instanceof Array ? target.functionMatch : [target.functionMatch]).filter((f) => {
if (typeof f !== 'function') {
this.emit('error', 'found functionMatch that is no function: ' + typeof f);
return false;
@@ -132,14 +135,10 @@ export default class ErrorMatcher extends EventEmitter {
}

match() {
require('./google-analytics').sendEvent('errorMatch', 'match');

this._gotoNext();
}

matchFirst() {
require('./google-analytics').sendEvent('errorMatch', 'first');

if (this.firstMatchId) {
this.goto(this.firstMatchId);
}
58 changes: 58 additions & 0 deletions src/linter-integration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import path from 'path';

class Linter {
constructor(registry) {
this.linter = registry.register({ name: 'Build' });
}
destroy() {
this.linter.dispose();
}
clear() {
this.linter.deleteMessages();
}
processMessages(messages, cwd) {
function extractRange(json) {
return [
[(json.line || 1) - 1, (json.col || 1) - 1],
[(json.line_end || json.line || 1) - 1, (json.col_end || json.col || 1) - 1]
];
}
function normalizePath(p) {
return path.isAbsolute(p) ? p : path.join(cwd, p);
}
function typeToSeverity(type) {
switch (type && type.toLowerCase()) {
case 'err':
case 'error':
return 'error';
case 'warn':
case 'warning':
return 'warning';
default:
return null;
}
}
this.linter.setMessages(
messages.map((match) => ({
type: match.type || 'Error',
text: !match.message && !match.html_message ? 'Error from build' : match.message,
html: match.message ? undefined : match.html_message,
filePath: normalizePath(match.file),
severity: typeToSeverity(match.type),
range: extractRange(match),
trace:
match.trace &&
match.trace.map((trace) => ({
type: trace.type || 'Trace',
text: !trace.message && !trace.html_message ? 'Trace in build' : trace.message,
html: trace.message ? undefined : trace.html_message,
filePath: trace.file && normalizePath(trace.file),
severity: typeToSeverity(trace.type) || 'info',
range: extractRange(trace)
}))
}))
);
}
}

export default Linter;
32 changes: 32 additions & 0 deletions src/loaders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import CSON from 'cson-parser';
import TOML from '@iarna/toml';
import JSON5 from 'json5';

export default {
cson(filePath, content) {
try {
return CSON.parse(content);
} catch (error) {
error.message = `TOML Error in ${filePath}:\n${error.message}`;
throw error;
}
},

json5(filePath, content) {
try {
return JSON5.parse(content);
} catch (error) {
error.message = `TOML Error in ${filePath}:\n${error.message}`;
throw error;
}
},

toml(filePath, content) {
try {
return TOML.parse(content);
} catch (error) {
error.message = `TOML Error in ${filePath}:\n${error.message}`;
throw error;
}
}
};
43 changes: 43 additions & 0 deletions src/log.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { name } from '../package.json';

const styleSheet = `
background-color: darkslateblue;
border-radius: 2px;
color: white;
line-height: 1.5;
padding: 1px 4px;
text-shadow: 0 1px 0px rgba(0, 0, 0, 0.2);
`;

function __console__(type, ...args) {
if (!atom?.inDevMode()) return;

args.unshift(`%c${name}%c`, styleSheet, '');
window.console[type](...args);
}

export default {
debug(...data) {
__console__('debug', ...data);
},

error(...data) {
__console__('error', ...data);
},

info(...data) {
__console__('info', ...data);
},

log(...data) {
__console__('log', ...data);
},

trace(...data) {
__console__('trace', ...data);
},

warn(...data) {
__console__('warn', ...data);
}
};
23 changes: 18 additions & 5 deletions lib/save-confirm-view.js → src/save-confirm-view.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
'use babel';

import { View } from 'atom-space-pen-views';

export default class SaveConfirmView extends View {
static content() {
this.div({ class: 'build-confirm overlay from-top' }, () => {
this.h3('You have unsaved changes');
this.div({ class: 'btn-container pull-right' }, () => {
this.button({ class: 'btn btn-success', outlet: 'saveBuildButton', title: 'Save and Build', click: 'saveAndConfirm' }, 'Save and build');
this.button({ class: 'btn btn-info', title: 'Build Without Saving', click: 'confirmWithoutSave' }, 'Build Without Saving');
this.button(
{
class: 'btn btn-primary',
outlet: 'saveBuildButton',
title: 'Save and Build',
click: 'saveAndConfirm'
},
'Save and build'
);
this.button(
{
class: 'btn btn-primary',
title: 'Build without Saving',
click: 'confirmWithoutSave'
},
'Build without Saving'
);
});
this.div({ class: 'btn-container pull-left' }, () => {
this.button({ class: 'btn btn-info', title: 'Cancel', click: 'cancel' }, 'Cancel');
this.button({ class: 'btn', title: 'Cancel', click: 'cancel' }, 'Cancel');
});
});
}
13 changes: 6 additions & 7 deletions lib/status-bar-view.js → src/status-bar-view.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
'use babel';

import { View } from 'atom-space-pen-views';
import Config from './config';

export default class StatusBarView extends View {
constructor(statusBar, ...args) {
super(...args);
this.statusBar = statusBar;
atom.config.observe('build.statusBar', () => this.attach());
atom.config.observe('build.statusBarPriority', () => this.attach());
Config.observe('statusBar', () => this.attach());
Config.observe('statusBarPriority', () => this.attach());
}

attach() {
this.destroy();

const orientation = atom.config.get('build.statusBar');
const orientation = Config.get('statusBar');
if ('Disable' === orientation) {
return;
}

this.statusBarTile = this.statusBar[`add${orientation}Tile`]({
item: this,
priority: atom.config.get('build.statusBarPriority')
priority: Config.get('statusBarPriority')
});

this.tooltip = atom.tooltips.add(this, {
@@ -42,7 +41,7 @@ export default class StatusBarView extends View {

static content() {
this.div({ id: 'build-status-bar', class: 'inline-block' }, () => {
this.a({ click: 'clicked', outlet: 'message'});
this.a({ click: 'clicked', outlet: 'message' });
});
}

254 changes: 254 additions & 0 deletions src/target-manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
import { CompositeDisposable } from 'atom';
import * as Utils from './utils';
import Config from './config';
import DevConsole from './log';
import EventEmitter from 'events';
import TargetsView from './targets-view';

class TargetManager extends EventEmitter {
constructor() {
super();

let projectPaths = atom.project.getPaths();

this.pathTargets = projectPaths.map((path) => this._defaultPathTarget(path));

atom.project.onDidChangePaths((newProjectPaths) => {
const addedPaths = newProjectPaths.filter((el) => projectPaths.indexOf(el) === -1);
const removedPaths = projectPaths.filter((el) => newProjectPaths.indexOf(el) === -1);
addedPaths.forEach((path) => this.pathTargets.push(this._defaultPathTarget(path)));
this.pathTargets = this.pathTargets.filter((pt) => -1 === removedPaths.indexOf(pt.path));
this.refreshTargets(addedPaths);
projectPaths = newProjectPaths;
});

atom.commands.add('atom-workspace', 'buildium:refresh-targets', () => this.refreshTargets());
atom.commands.add('atom-workspace', 'buildium:select-active-target', () => this.selectActiveTarget());
}

setBusyProvider(busyProvider) {
this.busyProvider = busyProvider;
}

_defaultPathTarget(path) {
return {
path: path,
loading: false,
targets: [],
instancedTools: [],
activeTarget: null,
tools: [],
subscriptions: new CompositeDisposable()
};
}

destroy() {
this.pathTargets.forEach((pathTarget) =>
pathTarget.tools.map((tool) => {
tool.removeAllListeners && tool.removeAllListeners('refresh');
tool.destructor && tool.destructor();
})
);
}

setTools(tools) {
this.tools = tools || [];
}

refreshTargets(refreshPaths) {
DevConsole.log('Refreshing targets');

refreshPaths = refreshPaths || atom.project.getPaths();

this.busyProvider && this.busyProvider.add(`Refreshing targets for ${refreshPaths.join(',')}`);
const pathPromises = refreshPaths.map((path) => {
const pathTarget = this.pathTargets.find((pt) => pt.path === path);
pathTarget.loading = true;

pathTarget.instancedTools = pathTarget.instancedTools.map((t) => t.removeAllListeners && t.removeAllListeners('refresh')).filter(() => false); // Just empty the array

const settingsPromise = this.tools
.map((Tool) => new Tool(path))
.filter((tool) => tool.isEligible())
.map((tool) => {
pathTarget.instancedTools.push(tool);
tool.on && tool.on('refresh', this.refreshTargets.bind(this, [path]));
return Promise.resolve()
.then(async () => await tool.settings())
.catch((err) => {
if (err instanceof SyntaxError) {
atom.notifications.addError('Invalid build file.', {
detail: 'You have a syntax error in your build file: ' + err.message,
dismissable: true
});
} else {
const toolName = tool.getNiceName();
atom.notifications.addError('Ooops. Something went wrong' + (toolName ? ' in the ' + toolName + ' build provider' : '') + '.', {
detail: err.message,
stack: err.stack,
dismissable: true
});
}
});
});

return Promise.all(settingsPromise)
.then((settings) => {
settings = Utils.uniquifySettings(
[].concat
.apply([], settings)
.filter(Boolean)
.map((setting) => Utils.getDefaultSettings(path, setting))
);

if (null === pathTarget.activeTarget || !settings.find((s) => s.name === pathTarget.activeTarget)) {
/* Active target has been removed or not set. Set it to the highest prio target */
pathTarget.activeTarget = settings[0] ? settings[0].name : undefined;
}

// CompositeDisposable cannot be reused, so we must create a new instance on every refresh
pathTarget.subscriptions.dispose();
pathTarget.subscriptions = new CompositeDisposable();

settings.forEach((setting, index) => {
if (setting.keymap && !setting.atomCommandName) {
setting.atomCommandName = `buildium:trigger:${setting.name}`;
}

if (setting.atomCommandName) {
pathTarget.subscriptions.add(
atom.commands.add('atom-workspace', setting.atomCommandName, (atomCommandName) => this.emit('trigger', atomCommandName))
);
}

if (setting.keymap) {
const keymapSpec = { 'atom-workspace, atom-text-editor': {} };
keymapSpec['atom-workspace, atom-text-editor'][setting.keymap] = setting.atomCommandName;
pathTarget.subscriptions.add(atom.keymaps.add(setting.name, keymapSpec));
}
});

pathTarget.targets = settings;
pathTarget.loading = false;

return pathTarget;
})
.catch((err) => {
atom.notifications.addError('Ooops. Something went wrong.', {
detail: err.message,
stack: err.stack,
dismissable: true
});
});
});

return Promise.all(pathPromises)
.then((pathTargets) => {
this.fillTargets(Utils.activePath(), false);
this.emit('refresh-complete');
this.busyProvider && this.busyProvider.remove(`Refreshing targets for ${refreshPaths.join(',')}`);

if (pathTargets.length === 0) {
return;
}

if (Config.get('notificationOnRefresh')) {
const rows = refreshPaths.map((path) => {
const pathTarget = this.pathTargets.find((pt) => pt.path === path);
if (!pathTarget) {
return `Targets ${path} no longer exists. Is build deactivated?`;
}
return `${pathTarget.targets.length} targets at: ${path}`;
});
atom.notifications.addInfo('Build targets parsed.', {
detail: rows.join('\n')
});
}
})
.catch((err) => {
atom.notifications.addError('Ooops. Something went wrong.', {
detail: err.message,
stack: err.stack,
dismissable: true
});
});
}

fillTargets(path, refreshOnEmpty = true) {
if (!this.targetsView) {
return;
}

const activeTarget = this.getActiveTarget(path);
activeTarget && this.targetsView.setActiveTarget(activeTarget.name);

this.getTargets(path, refreshOnEmpty)
.then((targets) => targets.map((t) => t.name))
.then((targetNames) => this.targetsView && this.targetsView.setItems(targetNames));
}

selectActiveTarget() {
if (Config.get('refreshOnShowTargetList')) {
this.refreshTargets();
}

const path = Utils.activePath();
if (!path) {
atom.notifications.addWarning('Unable to build.', {
detail: 'Open file is not part of any open project in Atom'
});
return;
}

this.targetsView = new TargetsView();

if (this.isLoading(path)) {
this.targetsView.setLoading('Loading project build targets\u2026');
} else {
this.fillTargets(path);
}

this.targetsView
.awaitSelection()
.then((newTarget) => {
this.setActiveTarget(path, newTarget);

this.targetsView = null;
})
.catch((err) => {
this.targetsView.setError(err.message);
this.targetsView = null;
});
}

getTargets(path, refreshOnEmpty = true) {
const pathTarget = this.pathTargets.find((pt) => pt.path === path);
if (!pathTarget) {
return Promise.resolve([]);
}

if (refreshOnEmpty && pathTarget.targets.length === 0) {
return this.refreshTargets([pathTarget.path]).then(() => pathTarget.targets);
}
return Promise.resolve(pathTarget.targets);
}

getActiveTarget(path) {
const pathTarget = this.pathTargets.find((pt) => pt.path === path);
if (!pathTarget) {
return null;
}
return pathTarget.targets.find((target) => target.name === pathTarget.activeTarget);
}

setActiveTarget(path, targetName) {
this.pathTargets.find((pt) => pt.path === path).activeTarget = targetName;
this.emit('new-active-target', path, this.getActiveTarget(path));
}

isLoading(path) {
return this.pathTargets.find((pt) => pt.path === path).loading;
}
}

export default TargetManager;
7 changes: 2 additions & 5 deletions lib/targets-view.js → src/targets-view.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
'use babel';

import { SelectListView } from 'atom-space-pen-views';

export default class TargetsView extends SelectListView {

constructor() {
super(...arguments);
this.show();
@@ -42,13 +39,13 @@ export default class TargetsView extends SelectListView {
viewForItem(targetName) {
const activeTarget = this.activeTarget;
return TargetsView.render(function () {
const activeClass = (targetName === activeTarget ? 'active' : '');
const activeClass = targetName === activeTarget ? 'active' : '';
this.li({ class: activeClass + ' build-target' }, targetName);
});
}

getEmptyMessage(itemCount) {
return (0 === itemCount) ? 'No targets found.' : 'No matches';
return 0 === itemCount ? 'No targets found.' : 'No matches';
}

awaitSelection() {
81 changes: 53 additions & 28 deletions lib/utils.js → src/utils.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
'use babel';

import fs from 'fs';
import { name, version } from '../package.json';
import path from 'path';

const uniquifySettings = (settings) => {
function uniquifySettings(settings) {
const genName = (name, index) => `${name} - ${index}`;
const newSettings = [];
settings.forEach(setting => {
settings.forEach((setting) => {
let i = 0;
let testName = setting.name;
while (newSettings.find(ns => ns.name === testName)) { // eslint-disable-line no-loop-func
while (newSettings.find((ns) => ns.name === testName)) {
testName = genName(setting.name, ++i);
}
newSettings.push({ ...setting, name: testName });
});
return newSettings;
};
}

const activePath = () => {
function activePath() {
const textEditor = atom.workspace.getActiveTextEditor();
if (!textEditor || !textEditor.getPath()) {
/* default to building the first one if no editor is active */
@@ -29,28 +28,31 @@ const activePath = () => {
}

/* otherwise, build the one in the root of the active editor */
return atom.project.getPaths().sort((a, b) => (b.length - a.length)).find(p => {
try {
const realpath = fs.realpathSync(p);
return fs.realpathSync(textEditor.getPath()).substr(0, realpath.length) === realpath;
} catch (err) {
/* Path no longer available. Possible network volume has gone down */
return false;
}
});
};
return atom.project
.getPaths()
.sort((a, b) => b.length - a.length)
.find(async (p) => {
try {
const realpath = await fs.promises.realpath(p);
return (await fs.promises.realpath(textEditor.getPath()).substr(0, realpath.length)) === realpath;
} catch (err) {
/* Path no longer available. Possible network volume has gone down */
return false;
}
});
}

const getDefaultSettings = (cwd, setting) => {
function getDefaultSettings(cwd, setting) {
return Object.assign({}, setting, {
env: setting.env || {},
args: setting.args || [],
cwd: setting.cwd || cwd,
sh: (undefined === setting.sh) ? true : setting.sh,
sh: undefined === setting.sh ? true : setting.sh,
errorMatch: setting.errorMatch || ''
});
};
}

const replace = (value = '', targetEnv) => {
function replace(value = '', targetEnv) {
if (!(typeof value === 'string')) {
return value;
}
@@ -62,18 +64,20 @@ const replace = (value = '', targetEnv) => {

const editor = atom.workspace.getActiveTextEditor();

const projectPaths = atom.project.getPaths().map(projectPath => {
const projectPaths = atom.project.getPaths().map(async (projectPath) => {
try {
return fs.realpathSync(projectPath);
} catch (e) { /* Do nothing. */ }
return await fs.promises.realpath(projectPath);
} catch (e) {
/* Do nothing. */
}
return null;
});

let projectPath = projectPaths[0];
if (editor && (undefined !== editor.getPath())) {
if (editor && undefined !== editor.getPath()) {
const activeFile = fs.realpathSync(editor.getPath());
const activeFilePath = path.dirname(activeFile);
projectPath = projectPaths.find(p => activeFilePath && activeFilePath.startsWith(p));
projectPath = projectPaths.find((p) => activeFilePath && activeFilePath.startsWith(p));
value = value.replace(/{FILE_ACTIVE}/g, activeFile);
value = value.replace(/{FILE_ACTIVE_PATH}/g, activeFilePath);
value = value.replace(/{FILE_ACTIVE_NAME}/g, path.basename(activeFile));
@@ -89,6 +93,27 @@ const replace = (value = '', targetEnv) => {
}

return value;
};
}

function capitalizedName() {
return `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
}

function getVersion() {
return `v${version}`;
}

function getBuildFilenames() {
return [
'package.json',
'.atom-build.json',
'.atom-build.yaml',
'.atom-build.yml',
'.atom-build.json5',
'.atom-build.js',
'.atom-build.cjs',
'.atom-build.toml'
];
}

export { uniquifySettings, activePath, getDefaultSettings, replace };
export { uniquifySettings, activePath, getDefaultSettings, replace, capitalizedName, getVersion, getBuildFilenames };
209 changes: 0 additions & 209 deletions styles/animations.less

This file was deleted.

55 changes: 34 additions & 21 deletions styles/build.less
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
@import "ui-variables";
@import "animations";
@import 'ui-variables';

.build {

min-width: 250px;
font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace;
font-weight: 600;
font-size: @font-size;

.resizer {
opacity: 0.0;
opacity: 0;
position: absolute;
border: solid 4px @base-border-color;
}

.heading {
-webkit-user-select: none;
line-height: 3.0em;
padding: 0 3px;
font-family: system-ui;
font-size: @font-size;
line-height: 3em;
padding: 0 5px;
border-left: 5px solid;
border-color: @text-color-subtle;

&.success {
animation: flash-background-success linear 1.2s;
border-color: @text-color-success;
}

&.error {
animation: flash-background-error linear 1.2s;
border-color: @text-color-error;
}

.heading-text {
@@ -35,19 +36,13 @@
&::before {
margin-right: 5px;
color: @text-color-error;
animation: flash linear infinite 1.0s;
}
}

.control-container {
float: right;
margin-left: @component-padding;

.btn {
color: @text-color-info;
margin: 0 1px;
}

.title {
float: left;

@@ -67,25 +62,30 @@
}

.output {
&.override-theme {
color: #fff;
background-color: #000;
}
color: @text-color;
background-color: @input-background-color;
padding: @component-padding;

.terminal {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
font-weight: normal;
font-family: var(--buildium-terminal-font-family, monospace);
font-size: var(--buildium-terminal-font-size);
> div {
white-space: nowrap;
font-size: inherit;
}
::selection {
background-color: @background-color-info;
color: @text-color-highlight;
}
}

.terminal-test {
background-color:none;
background-color: none;
position: absolute;
float: left;
visibility: hidden;
@@ -95,13 +95,26 @@
border: none;
}
}

.xterm {
.xterm-viewport {
background-color: inherit;
width: 100%;
height: 100%;
position: absolute;
}

.xterm-helpers {
display: none;
}
}
}

.opaque-hover {
transition: opacity 0.2s linear;
opacity: 0.6;
&:hover {
opacity: 1.0;
opacity: 1;
}
}

2 changes: 1 addition & 1 deletion styles/panel-left-right.less
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "ui-variables";
@import 'ui-variables';

atom-panel.left .build,
atom-panel.right .build {
2 changes: 1 addition & 1 deletion styles/panel-top-bottom.less
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "ui-variables";
@import 'ui-variables';

atom-panel.top .build,
atom-panel.bottom .build {