@unvt/charites 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.editorconfig +9 -0
  2. package/.github/workflows/build.yml +50 -0
  3. package/LICENSE +21 -0
  4. package/README.md +137 -0
  5. package/dist/cli.js +76 -0
  6. package/dist/commands/build.js +62 -0
  7. package/dist/commands/convert.js +89 -0
  8. package/dist/commands/init.js +33 -0
  9. package/dist/commands/serve.js +100 -0
  10. package/dist/lib/defaultValues.js +31 -0
  11. package/dist/lib/validate-style.js +24 -0
  12. package/dist/lib/yaml-parser.js +46 -0
  13. package/package.json +42 -0
  14. package/provider/default/app.css +7 -0
  15. package/provider/default/app.js +11 -0
  16. package/provider/default/index.html +13 -0
  17. package/provider/geolonia/app.css +7 -0
  18. package/provider/geolonia/app.js +11 -0
  19. package/provider/geolonia/index.html +12 -0
  20. package/provider/mapbox/app.css +7 -0
  21. package/provider/mapbox/app.js +13 -0
  22. package/provider/mapbox/index.html +13 -0
  23. package/src/cli.ts +83 -0
  24. package/src/commands/build.ts +64 -0
  25. package/src/commands/convert.ts +95 -0
  26. package/src/commands/init.ts +29 -0
  27. package/src/commands/serve.ts +105 -0
  28. package/src/lib/defaultValues.ts +36 -0
  29. package/src/lib/validate-style.ts +22 -0
  30. package/src/lib/yaml-parser.ts +51 -0
  31. package/test/build.spec.ts +36 -0
  32. package/test/convert.spec.ts +43 -0
  33. package/test/data/convert.json +23 -0
  34. package/test/data/error.yml +1 -0
  35. package/test/data/example.yml +20 -0
  36. package/test/data/layers/background.yml +4 -0
  37. package/test/data/layers/water.yml +8 -0
  38. package/test/data/names.yml +3 -0
  39. package/test/data/style.json +33 -0
  40. package/test/data/style.yml +12 -0
  41. package/test/validate-style.spec.ts +18 -0
  42. package/test/yaml-parser.spec.ts +25 -0
  43. package/tsconfig.json +19 -0
package/.editorconfig ADDED
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 2
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
@@ -0,0 +1,50 @@
1
+ # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2
+ # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3
+
4
+ name: build
5
+
6
+ on:
7
+ push:
8
+ branches:
9
+ - main
10
+ tags: ['*']
11
+ pull_request:
12
+ branches:
13
+ - main
14
+
15
+ jobs:
16
+ build:
17
+ runs-on: ubuntu-latest
18
+
19
+ strategy:
20
+ matrix:
21
+ node-version: [14.x, 16.x]
22
+
23
+ steps:
24
+ - uses: actions/checkout@v2
25
+ - name: Use Node.js ${{ matrix.node-version }}
26
+ uses: actions/setup-node@v1
27
+ with:
28
+ node-version: ${{ matrix.node-version }}
29
+ - run: npm install
30
+ - run: npm test
31
+
32
+ publish:
33
+ name: 'Publish npm package'
34
+ runs-on: ubuntu-latest
35
+ needs: build
36
+ if: startsWith(github.ref, 'refs/tags/v')
37
+ steps:
38
+ - uses: actions/checkout@v2
39
+ # Setup .npmrc file to publish to npm
40
+ - uses: actions/setup-node@v1
41
+ with:
42
+ tag_name: 'v%s'
43
+ node-version: '14.x'
44
+ registry-url: 'https://registry.npmjs.org'
45
+ scope: '@unvt'
46
+ - run: npm install
47
+ - run: npm run build
48
+ - run: npm publish --access=public
49
+ env:
50
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Geolonia Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # Charites
2
+
3
+ An easy, intuitive, and efficient command-line tool for writing vector map styles compatible with the [Mapbox](https://docs.mapbox.com/mapbox-gl-js/style-spec/) and [MapLibre](https://maplibre.org/maplibre-gl-js-docs/style-spec/) Style Specification in YAML.
4
+ With YAML format's readability, JSON compiler, linter, and live style viewer on a local browser, you can simplify your map styling workflow.
5
+
6
+ In Greek mythology, the [Charites](https://en.wikipedia.org/wiki/Charites) are the three goddesses of charm, beauty, and human creativity. They are believed to have been worshipped not only by artists but also by those who aspired to technology to infuse them with a creative spirit.
7
+
8
+ ## Features
9
+
10
+ - Initiate a project from scratch, or convert an existing `style.json` file to generate YAML style files.
11
+ - Write styles in a simple YAML format.
12
+ - Divide groups of layers in to multiple files for better readability and mantainability. `!!inc/file <relative-path-to-the-file>`
13
+ - Use variables like `$backgroundColor` and `$waterColor` to style effectively.
14
+ - Compile YAML to a single style.json file, with a format linter.
15
+ - Use `--provider mapbox` to validate your style against Mapbox GL JS v2.x
16
+ - Run `charites serve <source>` to preview your style live while you make changes in a browser.
17
+
18
+ Example: https://github.com/miya0001/style-template
19
+
20
+ ## Install
21
+
22
+ ```
23
+ $ npm install -g @unvt/charites
24
+ ```
25
+
26
+ Then try:
27
+
28
+ ```
29
+ $ charites help
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ```
35
+ $ charites help
36
+ Usage: charites [options] [command]
37
+
38
+ Options:
39
+ --provider [provider] your map service. e.g. `mapbox`, `geolonia`
40
+ --mapbox-access-token [mapboxAccessToken] Access Token for the Mapbox
41
+ -h, --help display help for command
42
+
43
+ Commands:
44
+ init <file> initialize a style JSON
45
+ convert <source> [destination] convert the style JSON to YAML
46
+ build [options] <source> [destination] build a style JSON from the YAML
47
+ serve <source> serve your map locally
48
+ help [command] display help for command
49
+ ```
50
+
51
+ ## Global Options
52
+
53
+ Charites has two global options that are common to all commands.
54
+
55
+ - `--provider` - `mapbox`, `geolonia`, or `default`. When not specified, default or the value in the configuration file will be used.
56
+ - `mapbox` - The format linter runs against the Mapbox GL JS v2.x compatible specification.
57
+ - `geolonia` and `default` - the format linter runs against the MapLibre GL JS compatible specification.
58
+ - `--mapbox-access-token` - Set your access-token when styling for Mapbox.
59
+
60
+ # Configuration
61
+
62
+ The global options for Charites can be stored in a configuration file written in YAML.
63
+
64
+ The config file will be automatically created to the following path the first time the charites command is executed.
65
+
66
+ ```
67
+ ~/.charites/config.yml
68
+ ```
69
+
70
+ Global options can be specified as follows:
71
+
72
+
73
+ ```
74
+ provider: mapbox
75
+ mapboxAccessToken: xxxx
76
+ ```
77
+
78
+ With the example above, you get the same result as `charites --provider mapbox --mapbox-access-token xxxx`.
79
+
80
+ ## Examples
81
+
82
+ Build `style.json` from `style.yml`:
83
+
84
+ ```
85
+ charites build style.yml style.json
86
+ ```
87
+
88
+ Add `-c` or `--compact-output` to minify the JSON
89
+
90
+ ```
91
+ charites build style.yml style.json -c
92
+ ```
93
+
94
+ Convert `style.json` to `style.yml`:
95
+
96
+ ```
97
+ charites convert style.json style.yml
98
+ ```
99
+
100
+ Load JSON as a standard input to generate `style.yml`:
101
+
102
+ ```
103
+ curl http://example.com/style.json | charites convert - style.yml
104
+ ```
105
+
106
+ Launch a live preview of your map style in your local environment:
107
+
108
+ ```
109
+ charites serve style.yml
110
+ ```
111
+
112
+ For Mapbox users:
113
+
114
+ ```
115
+ charites serve style.yml --provider mapbox --mapbox-access-token xxxx
116
+ ```
117
+
118
+ ## Contributing
119
+
120
+ ### Development
121
+
122
+ ```
123
+ $ git clone https://github.com/geolonia/charites.git
124
+ $ cd charites
125
+ $ npm install
126
+ $ npm run build
127
+ $ npm install -g .
128
+ ```
129
+ Then run:
130
+
131
+ ```
132
+ $ charites help
133
+ ```
134
+
135
+ ## License
136
+
137
+ MIT
package/dist/cli.js ADDED
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const init_1 = require("./commands/init");
10
+ const convert_1 = require("./commands/convert");
11
+ const build_1 = require("./commands/build");
12
+ const serve_1 = require("./commands/serve");
13
+ const defaultValues_1 = require("./lib/defaultValues");
14
+ const program = new commander_1.Command();
15
+ const error = (message) => {
16
+ console.error(message.toString());
17
+ process.exit(1);
18
+ };
19
+ program
20
+ .option('--provider [provider]', 'your map service. e.g. `mapbox`, `geolonia`')
21
+ .option('--mapbox-access-token [mapboxAccessToken]', 'Access Token for the Mapbox');
22
+ program
23
+ .command('init <file>')
24
+ .description('initialize a style JSON')
25
+ .action((file) => {
26
+ try {
27
+ init_1.init(file);
28
+ }
29
+ catch (e) {
30
+ error(e);
31
+ }
32
+ });
33
+ program
34
+ .command('convert <source> [destination]')
35
+ .description('convert the style JSON to YAML')
36
+ .action((source, destination) => {
37
+ try {
38
+ convert_1.convert(source, destination);
39
+ }
40
+ catch (e) {
41
+ error(e);
42
+ }
43
+ });
44
+ program
45
+ .command('build <source> [destination]')
46
+ .description('build a style JSON from the YAML')
47
+ .option('-c, --compact-output', 'build a minified style JSON')
48
+ .action((source, destination, buildOptions) => {
49
+ const options = program.opts();
50
+ options.compactOutput = buildOptions.compactOutput;
51
+ if (!fs_1.default.existsSync(defaultValues_1.defaultSettings.configFile)) {
52
+ fs_1.default.writeFileSync(defaultValues_1.defaultSettings.configFile, `provider: ${options.provider || 'default'}`);
53
+ }
54
+ try {
55
+ build_1.build(source, destination, options);
56
+ }
57
+ catch (e) {
58
+ error(e);
59
+ }
60
+ });
61
+ program
62
+ .command('serve <source>')
63
+ .description('serve your map locally')
64
+ .action((source) => {
65
+ const options = program.opts();
66
+ if (!fs_1.default.existsSync(defaultValues_1.defaultSettings.configFile)) {
67
+ fs_1.default.writeFileSync(defaultValues_1.defaultSettings.configFile, `provider: ${options.provider || 'default'}`);
68
+ }
69
+ try {
70
+ serve_1.serve(source, program.opts());
71
+ }
72
+ catch (e) {
73
+ error(e);
74
+ }
75
+ });
76
+ program.parse(process.argv);
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.build = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const yaml_parser_1 = require("../lib/yaml-parser");
10
+ const validate_style_1 = require("../lib/validate-style");
11
+ const defaultValues_1 = require("../lib/defaultValues");
12
+ const jsonminify_1 = __importDefault(require("jsonminify"));
13
+ function build(source, destination, options) {
14
+ let sourcePath = path_1.default.resolve(process.cwd(), source);
15
+ // The `source` is absolute path.
16
+ if (source.match(/^\//)) {
17
+ sourcePath = source;
18
+ }
19
+ if (!fs_1.default.existsSync(sourcePath)) {
20
+ throw `${sourcePath}: No such file or directory`;
21
+ }
22
+ let destinationPath = "";
23
+ if (destination) {
24
+ if (destination.match(/^\//)) {
25
+ destinationPath = destination;
26
+ }
27
+ else {
28
+ destinationPath = path_1.default.resolve(process.cwd(), destination);
29
+ }
30
+ }
31
+ else {
32
+ destinationPath = path_1.default.join(path_1.default.dirname(sourcePath), `${path_1.default.basename(source, '.yml')}.json`);
33
+ }
34
+ let provider = defaultValues_1.defaultValues.provider;
35
+ if (options.provider) {
36
+ provider = options.provider;
37
+ }
38
+ let style = '';
39
+ try {
40
+ const _style = yaml_parser_1.parser(sourcePath);
41
+ validate_style_1.validateStyle(_style, provider);
42
+ style = JSON.stringify(_style, null, ' ');
43
+ if (options.compactOutput) {
44
+ style = jsonminify_1.default(style);
45
+ }
46
+ }
47
+ catch (err) {
48
+ if (err) {
49
+ throw err;
50
+ }
51
+ else {
52
+ throw `${sourcePath}: Invalid YAML syntax`;
53
+ }
54
+ }
55
+ try {
56
+ fs_1.default.writeFileSync(destinationPath, style);
57
+ }
58
+ catch (err) {
59
+ throw `${destinationPath}: Permission denied`;
60
+ }
61
+ }
62
+ exports.build = build;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.convert = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const js_yaml_1 = __importDefault(require("js-yaml"));
10
+ const readline_1 = __importDefault(require("readline"));
11
+ // TODO: Type of style should be loaded from maplibre or mapbox style spec.
12
+ const writeYaml = (destinationPath, style) => {
13
+ const layers = [];
14
+ for (let i = 0; i < style.layers.length; i++) {
15
+ const layer = style.layers[i];
16
+ const layerYml = js_yaml_1.default.dump(layer);
17
+ const fileName = `${style.layers[i].id}.yml`;
18
+ const dirName = path_1.default.join(path_1.default.dirname(destinationPath), 'layers');
19
+ fs_1.default.mkdirSync(dirName, { recursive: true });
20
+ fs_1.default.writeFileSync(path_1.default.join(dirName, fileName), layerYml);
21
+ layers.push(`!!inc/file ${path_1.default.join('layers', fileName)}`);
22
+ }
23
+ style.layers = layers;
24
+ fs_1.default.writeFileSync(destinationPath, js_yaml_1.default.dump(style).replace(/'\!\!inc\/file layers\/.+\.yml'/g, function (match) {
25
+ return match.replace(/'/g, '');
26
+ }));
27
+ };
28
+ const getDestinationPath = (destination, sourcePath = '') => {
29
+ let destinationPath;
30
+ if (destination) {
31
+ if (destination.match(/^\//)) {
32
+ destinationPath = destination;
33
+ }
34
+ else {
35
+ destinationPath = path_1.default.resolve(process.cwd(), destination);
36
+ }
37
+ }
38
+ else {
39
+ if (sourcePath) {
40
+ destinationPath = path_1.default.join(path_1.default.dirname(sourcePath), `${path_1.default.basename(sourcePath, '.json')}.yml`);
41
+ }
42
+ else {
43
+ destinationPath = path_1.default.join(process.cwd(), 'style.yml');
44
+ }
45
+ }
46
+ return destinationPath;
47
+ };
48
+ function convert(source, destination) {
49
+ let style, sourcePath;
50
+ if ('-' === source) {
51
+ const rl = readline_1.default.createInterface({
52
+ input: process.stdin,
53
+ terminal: false
54
+ });
55
+ const lines = [];
56
+ rl.on("line", (line) => {
57
+ lines.push(line);
58
+ });
59
+ rl.on("close", () => {
60
+ const style = JSON.parse(lines.join(''));
61
+ const destinationPath = getDestinationPath(destination);
62
+ try {
63
+ writeYaml(destinationPath, style);
64
+ }
65
+ catch (err) {
66
+ throw `${destinationPath}: Permission denied`;
67
+ }
68
+ });
69
+ }
70
+ else {
71
+ sourcePath = path_1.default.resolve(process.cwd(), source);
72
+ // The `source` is absolute path.
73
+ if (source.match(/^\//)) {
74
+ sourcePath = source;
75
+ }
76
+ if (!fs_1.default.existsSync(sourcePath)) {
77
+ throw `${sourcePath}: No such file or directory`;
78
+ }
79
+ style = JSON.parse(fs_1.default.readFileSync(sourcePath, 'utf-8'));
80
+ const destinationPath = getDestinationPath(destination, sourcePath);
81
+ try {
82
+ writeYaml(destinationPath, style);
83
+ }
84
+ catch (err) {
85
+ throw `${destinationPath}: Permission denied`;
86
+ }
87
+ }
88
+ }
89
+ exports.convert = convert;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.init = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const js_yaml_1 = __importDefault(require("js-yaml"));
10
+ // TODO: We need type definition for style.
11
+ const styleRoot = {
12
+ version: 8,
13
+ name: "My Style",
14
+ sprite: "",
15
+ glyphs: "",
16
+ sources: {},
17
+ layers: []
18
+ };
19
+ function init(file) {
20
+ const styleYAML = js_yaml_1.default.dump(styleRoot);
21
+ let stylePath = path_1.default.resolve(process.cwd(), file);
22
+ // The `source` is absolute path.
23
+ if (file.match(/^\//)) {
24
+ stylePath = file;
25
+ }
26
+ try {
27
+ fs_1.default.writeFileSync(stylePath, styleYAML);
28
+ }
29
+ catch (err) {
30
+ throw `${stylePath}: Permission denied`;
31
+ }
32
+ }
33
+ exports.init = init;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.serve = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const http_1 = __importDefault(require("http"));
10
+ const open_1 = __importDefault(require("open"));
11
+ const ws_1 = require("ws");
12
+ const node_watch_1 = __importDefault(require("node-watch"));
13
+ const yaml_parser_1 = require("../lib/yaml-parser");
14
+ const validate_style_1 = require("../lib/validate-style");
15
+ const defaultValues_1 = require("../lib/defaultValues");
16
+ function serve(source, options) {
17
+ const port = process.env.PORT || 8080;
18
+ let sourcePath = path_1.default.resolve(process.cwd(), source);
19
+ let provider = defaultValues_1.defaultValues.provider;
20
+ if (options.provider) {
21
+ provider = options.provider;
22
+ }
23
+ // The `source` is absolute path.
24
+ if (source.match(/^\//)) {
25
+ sourcePath = source;
26
+ }
27
+ if (!fs_1.default.existsSync(sourcePath)) {
28
+ throw `${sourcePath}: No such file or directory`;
29
+ }
30
+ const server = http_1.default.createServer((req, res) => {
31
+ const url = (req.url || '').replace(/\?.*/, '');
32
+ const dir = path_1.default.join(defaultValues_1.defaultValues.providerDir, provider);
33
+ switch (url) {
34
+ case '/':
35
+ res.statusCode = 200;
36
+ res.setHeader('Content-Type', 'text/html; charset=UTF-8');
37
+ const content = fs_1.default.readFileSync(path_1.default.join(dir, 'index.html'), 'utf-8');
38
+ res.end(content);
39
+ break;
40
+ case '/style.json':
41
+ const style = yaml_parser_1.parser(sourcePath);
42
+ try {
43
+ validate_style_1.validateStyle(style, provider);
44
+ }
45
+ catch (error) {
46
+ console.log(error);
47
+ }
48
+ res.statusCode = 200;
49
+ res.setHeader('Content-Type', 'application/json; charset=UTF-8');
50
+ res.end(JSON.stringify(style));
51
+ break;
52
+ case '/app.css':
53
+ res.statusCode = 200;
54
+ res.setHeader('Content-Type', 'text/css; charset=UTF-8');
55
+ const css = fs_1.default.readFileSync(path_1.default.join(dir, 'app.css'), 'utf-8');
56
+ res.end(css);
57
+ break;
58
+ case `/app.js`:
59
+ res.statusCode = 200;
60
+ res.setHeader('Content-Type', 'application/javascript; charset=UTF-8');
61
+ try {
62
+ const app = fs_1.default.readFileSync(path_1.default.join(dir, 'app.js'), 'utf-8');
63
+ const js = app.replace('___PORT___', `${port}`)
64
+ .replace('___MAPBOX_ACCESS_TOKEN___', `${options.mapboxAccessToken || defaultValues_1.defaultValues.mapboxAccessToken}`);
65
+ res.end(js);
66
+ }
67
+ catch (e) {
68
+ throw `Invalid provider: ${provider}`;
69
+ }
70
+ break;
71
+ }
72
+ });
73
+ server.listen(port, () => {
74
+ console.log(`Provider: ${provider}`);
75
+ console.log(`Loading your style: ${sourcePath}`);
76
+ console.log(`Your map is running on http://localhost:${port}/\n`);
77
+ open_1.default(`http://localhost:${port}`);
78
+ });
79
+ const wss = new ws_1.WebSocketServer({ server });
80
+ wss.on('connection', (ws) => {
81
+ node_watch_1.default(path_1.default.dirname(sourcePath), { recursive: true, filter: /\.yml$/ }, (event, file) => {
82
+ console.log(`${(event || '').toUpperCase()}: ${file}`);
83
+ try {
84
+ const style = yaml_parser_1.parser(sourcePath);
85
+ try {
86
+ validate_style_1.validateStyle(style, provider);
87
+ }
88
+ catch (error) {
89
+ console.log(error);
90
+ }
91
+ ws.send(JSON.stringify(style));
92
+ }
93
+ catch (e) {
94
+ // Nothing to do
95
+ }
96
+ });
97
+ });
98
+ return server;
99
+ }
100
+ exports.serve = serve;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.defaultSettings = exports.defaultValues = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const os_1 = __importDefault(require("os"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const js_yaml_1 = __importDefault(require("js-yaml"));
11
+ const homedir = os_1.default.homedir();
12
+ const defaultProvider = "default";
13
+ const configDir = path_1.default.join(homedir, '.charites');
14
+ fs_1.default.mkdirSync(configDir, { recursive: true });
15
+ const configFile = path_1.default.join(configDir, 'config.yml');
16
+ let config = { provider: '', providerDir: '', mapboxAccessToken: '' };
17
+ try {
18
+ const yaml = fs_1.default.readFileSync(configFile, 'utf-8');
19
+ config = js_yaml_1.default.load(yaml);
20
+ }
21
+ catch (e) {
22
+ // nothing to do
23
+ }
24
+ exports.defaultValues = {
25
+ provider: config.provider || defaultProvider,
26
+ providerDir: path_1.default.join(path_1.default.dirname(path_1.default.dirname(__dirname)), 'provider'),
27
+ mapboxAccessToken: config.mapboxAccessToken || ''
28
+ };
29
+ exports.defaultSettings = {
30
+ configFile: configFile
31
+ };
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateStyle = void 0;
4
+ const maplibreStyleSpec = require('@maplibre/maplibre-gl-style-spec');
5
+ const mapboxStyleSpec = require('@mapbox/mapbox-gl-style-spec');
6
+ function validateStyle(style, provider = "default") {
7
+ let result = [];
8
+ if ('mapbox' === provider) {
9
+ result = mapboxStyleSpec.validate(style);
10
+ }
11
+ else {
12
+ result = maplibreStyleSpec.validate(style);
13
+ }
14
+ const errors = [];
15
+ for (let i = 0; i < result.length; i++) {
16
+ if (result[i].message) {
17
+ errors.push(result[i].message);
18
+ }
19
+ }
20
+ if (errors.length) {
21
+ throw `\u001b[31mError:\u001b[0m ${errors.join("\n\u001b[31mError:\u001b[0m ")}`;
22
+ }
23
+ }
24
+ exports.validateStyle = validateStyle;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parser = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const js_yaml_1 = __importDefault(require("js-yaml"));
9
+ const yamlinc = require('yaml-include');
10
+ function parser(file) {
11
+ yamlinc.setBaseFile(file);
12
+ const yaml = fs_1.default.readFileSync(file, 'utf8');
13
+ const obj = js_yaml_1.default.load(yaml, {
14
+ schema: yamlinc.YAML_INCLUDE_SCHEMA,
15
+ filename: file,
16
+ json: true
17
+ });
18
+ const styleObj = {};
19
+ let variables = {};
20
+ for (const key in obj) {
21
+ if (key.match(/^\$/)) {
22
+ variables[key] = obj[key];
23
+ }
24
+ else {
25
+ styleObj[key] = obj[key];
26
+ }
27
+ }
28
+ // Handle all nested variables.
29
+ while (JSON.stringify(Object.values(variables)).match(/\$/)) {
30
+ for (const key in variables) {
31
+ for (const variable in variables) {
32
+ let _value = JSON.stringify(variables[key]);
33
+ const regex = new RegExp(`\"\\${variable}\"`, 'g');
34
+ _value = _value.replace(regex, JSON.stringify(variables[variable]));
35
+ variables[key] = JSON.parse(_value);
36
+ }
37
+ }
38
+ }
39
+ let style = JSON.stringify(styleObj);
40
+ for (const key in variables) {
41
+ const regex = new RegExp(`\"\\${key}\"`, 'g');
42
+ style = style.replace(regex, JSON.stringify(variables[key]));
43
+ }
44
+ return JSON.parse(style);
45
+ }
46
+ exports.parser = parser;