├── test ├── node.ts ├── browser.ts ├── modules.ts └── index.html ├── website ├── src │ ├── about.md │ ├── theme.json │ └── home.md ├── .eslintignore ├── static │ └── images │ │ ├── hero.jpg │ │ ├── favicon.ico │ │ ├── uber-logo.png │ │ ├── icon-target.svg │ │ ├── icon-custom.svg │ │ └── icon-react.svg ├── package.json ├── .gitignore └── gatsby-config.js ├── docs ├── BASEURL ├── wip │ └── gatsby-theme-ocular │ │ ├── upgrade-guide.md │ │ ├── get-started.md │ │ └── README.md ├── README.md └── table-of-contents.json ├── .eslintignore ├── .prettierignore ├── modules └── dev-tools │ ├── templates │ ├── .prettierignore │ ├── .eslintignore │ ├── .prettierrc │ ├── .nycrc │ ├── tsconfig.json │ └── .eslintrc.gatsby-todo │ ├── docs │ ├── cli │ │ ├── ocular-clean.md │ │ ├── ocular-build.md │ │ ├── ocular-metrics.md │ │ ├── ocular-bootstrap.md │ │ ├── ocular-lint.md │ │ ├── ocular-publish.md │ │ ├── ocular-bump.md │ │ ├── ocular-test.md │ │ └── ocular-tsify.md │ ├── upgrade-guide.md │ ├── faq.md │ ├── api-reference │ │ ├── get-prettier-config.md │ │ ├── get-eslint-config.md │ │ └── get-babel-config.md │ ├── whats-new.md │ └── README.md │ ├── src │ ├── configuration │ │ ├── eslint-config-uber-es2015 │ │ │ ├── miscellaneous.json │ │ │ ├── best-practices.json │ │ │ ├── stylistic-issues.json │ │ │ ├── ecmascript-6.json │ │ │ └── eslintrc.json │ │ ├── eslint-config-uber-jsx │ │ │ ├── best-practices.json │ │ │ ├── stylistic-issues.json │ │ │ ├── miscellaneous.json │ │ │ └── eslintrc.json │ │ ├── eslint-config-uber-es5 │ │ │ ├── strict-mode.json │ │ │ ├── miscellaneous.json │ │ │ ├── variables.json │ │ │ ├── node-js-and-common-js.json │ │ │ ├── eslintrc.json │ │ │ ├── best-practices.json │ │ │ ├── stylistic-issues.json │ │ │ └── errors.json │ │ ├── index.ts │ │ ├── get-prettier-config.ts │ │ ├── vite.config.js │ │ ├── get-babel-config.ts │ │ ├── get-esbuild-config.ts │ │ └── get-eslint-config.ts │ ├── index.ts │ ├── utils │ │ ├── types.ts │ │ └── utils.ts │ ├── helpers │ │ ├── cjs-register.cjs │ │ ├── get-config.ts │ │ ├── get-cjs-entry-points.ts │ │ ├── aliases.ts │ │ ├── esm-loader.js │ │ └── get-ocular-config.ts │ ├── build-cjs.ts │ ├── ts-plugins │ │ ├── ts-transform-inline-webgl-constants │ │ │ └── index.ts │ │ ├── ts-transform-version-inline │ │ │ └── index.ts │ │ ├── ts-transform-append-extension │ │ │ └── index.ts │ │ └── ts-transform-remove-glsl-comments │ │ │ └── index.ts │ └── test.ts │ ├── README.md │ ├── test │ ├── ts-plugins │ │ ├── ts-transform-remove-glsl-comments │ │ │ ├── test-case-0.ts │ │ │ ├── test-case-0-expected.ts │ │ │ ├── test-case-2-expected.ts │ │ │ ├── test-case-2.ts │ │ │ ├── test-case-1-expected.ts │ │ │ ├── test-case-1.ts │ │ │ └── index.spec.ts │ │ ├── ts-transform-version-inline.spec.ts │ │ ├── ts-transform-inline-webgl-constants.spec.ts │ │ ├── ts-transform-append-extension.spec.ts │ │ └── test-transformer.ts │ ├── lib │ │ ├── utils.spec.ts │ │ └── configuration.spec.ts │ └── index.ts │ ├── scripts │ ├── shell.js │ ├── lint.js │ ├── test.js │ ├── build.js │ ├── clean.js │ ├── metrics.js │ ├── publish.js │ ├── bootstrap.js │ ├── clean.sh │ ├── bootstrap.sh │ ├── bundle.js │ ├── test.sh │ ├── metrics.sh │ ├── publish.sh │ ├── lint.sh │ ├── bump.js │ └── build.sh │ ├── tsconfig.json │ ├── package.json │ └── CHANGELOG.md ├── .prettierrc.cjs ├── scripts └── remove-refs-to-unpm.pl ├── .travis.yml ├── babel.config.cjs ├── tsconfig.build.json ├── .markdownlintrc ├── examples └── dev-tools │ ├── .eslintrc.js │ ├── .prettierrc.js │ ├── babel.config.js │ ├── ocular-dev-tools.config.js │ ├── src │ └── app.js │ ├── index.html │ ├── package.json │ ├── dist │ ├── es5 │ │ ├── app.js.map │ │ └── app.js │ └── esm │ │ ├── app.js.map │ │ └── app.js │ └── webpack.config.js ├── .gitignore ├── README.md ├── .ocularrc.js ├── tsconfig.json ├── dev-docs └── RFCs │ ├── README.md │ └── v1.0 │ └── gatsby-rfc.md ├── .eslintrc.cjs ├── .github └── workflows │ └── test.yml ├── LICENSE └── package.json /test/node.ts: -------------------------------------------------------------------------------- 1 | import './modules'; 2 | -------------------------------------------------------------------------------- /website/src/about.md: -------------------------------------------------------------------------------- 1 | # About us 2 | -------------------------------------------------------------------------------- /test/browser.ts: -------------------------------------------------------------------------------- 1 | import './modules'; 2 | -------------------------------------------------------------------------------- /docs/BASEURL: -------------------------------------------------------------------------------- 1 | https://uber-web.github.io/ocular -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | test/ 3 | test-case-*.ts 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/dist*/**/*.js 2 | test-case-*.ts -------------------------------------------------------------------------------- /website/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /test/modules.ts: -------------------------------------------------------------------------------- 1 | import '../modules/dev-tools/test'; 2 | -------------------------------------------------------------------------------- /website/src/theme.json: -------------------------------------------------------------------------------- 1 | { 2 | "primary400": "#FFC000" 3 | } -------------------------------------------------------------------------------- /modules/dev-tools/templates/.prettierignore: -------------------------------------------------------------------------------- 1 | **/dist*/**/*.js 2 | -------------------------------------------------------------------------------- /modules/dev-tools/templates/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | dist/* 3 | coverage/* 4 | -------------------------------------------------------------------------------- /website/static/images/hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donmccurdy/ocular/master/website/static/images/hero.jpg -------------------------------------------------------------------------------- /website/static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donmccurdy/ocular/master/website/static/images/favicon.ico -------------------------------------------------------------------------------- /website/static/images/uber-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donmccurdy/ocular/master/website/static/images/uber-logo.png -------------------------------------------------------------------------------- /modules/dev-tools/docs/cli/ocular-clean.md: -------------------------------------------------------------------------------- 1 | # ocular-clean 2 | 3 | Remove all transpiled files in preparation for a new build. 4 | -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | const {getPrettierConfig} = require('ocular-dev-tools/configuration'); 2 | 3 | module.exports = getPrettierConfig(); 4 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/cli/ocular-build.md: -------------------------------------------------------------------------------- 1 | # ocular-build 2 | 3 | Build the source. 4 | 5 | ```bash 6 | ocular-build [module_name] 7 | ``` 8 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es2015/miscellaneous.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "prefer-reflect": 0 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-jsx/best-practices.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-invalid-this": 0 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /modules/dev-tools/templates/.prettierrc: -------------------------------------------------------------------------------- 1 | printWidth: 100 2 | semi: true 3 | singleQuote: true 4 | trailingComma: none 5 | bracketSpacing: false 6 | -------------------------------------------------------------------------------- /scripts/remove-refs-to-unpm.pl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | perl -pi -e 's/unpm\.uberinternal\.com/registry\.yarnpkg\.com/g' `find . -name yarn.lock` 4 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/upgrade-guide.md: -------------------------------------------------------------------------------- 1 | # Upgrade Guide 2 | 3 | ## ocular-dev-tools 1.0.0 4 | 5 | Functional entry points replace subpath imports 6 | -------------------------------------------------------------------------------- /modules/dev-tools/src/index.ts: -------------------------------------------------------------------------------- 1 | export {getOcularConfig} from './helpers/get-ocular-config.js'; 2 | 3 | export type {OcularConfig} from './helpers/get-ocular-config.js'; 4 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es5/strict-mode.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "strict": [ 4 | 2, 5 | "global" 6 | ] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/faq.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | ## How to debug ocular builds 4 | 5 | * Set `logLevel` in ocular-config.js, numbers between `1`-`4` give increasing levels of logging. 6 | -------------------------------------------------------------------------------- /modules/dev-tools/README.md: -------------------------------------------------------------------------------- 1 | # ocular-dev-tools 2 | 3 | Experimental dev tools for our open source Javascript frameworks 4 | 5 | For documentation, see [https://uber-web.github.io/ocular] 6 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-jsx/stylistic-issues.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "jsx-quotes": [ 4 | 2, 5 | "prefer-double" 6 | ] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/cli/ocular-metrics.md: -------------------------------------------------------------------------------- 1 | # ocular-metrics 2 | 3 | Bundle the source and report the bundle size. 4 | 5 | ## Configuration 6 | 7 | [Configurations](#ocular-dev-tools-1): `entry` 8 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/cli/ocular-bootstrap.md: -------------------------------------------------------------------------------- 1 | # ocular-bootstrap 2 | 3 | Installing dependencies for a monorepo. 4 | 5 | 6 | ## Remarks 7 | 8 | Uses yarn workspaces and lerna to initialize monorepos. 9 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0.ts: -------------------------------------------------------------------------------- 1 | export function getTime() { 2 | // Template literal that is not shader 3 | return `The time is ${Date.now()}`; 4 | } 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | os: linux 3 | sudo: required 4 | dist: trusty 5 | addons: 6 | node_js: 7 | - '12' 8 | - '14' 9 | install: 10 | - yarn bootstrap 11 | script: 12 | - npm run test 13 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0-expected.ts: -------------------------------------------------------------------------------- 1 | export function getTime() { 2 | // Template literal that is not shader 3 | return `The time is ${Date.now()}`; 4 | } 5 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | luma.gl tests 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /babel.config.cjs: -------------------------------------------------------------------------------- 1 | const {getBabelConfig} = require('ocular-dev-tools/configuration'); 2 | 3 | module.exports = getBabelConfig({ 4 | react: true, 5 | overrides: { 6 | plugins: ['@babel/syntax-import-assertions'] 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es2015/best-practices.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "accessor-pairs": [ 4 | 2, 5 | { 6 | "getWithoutSet": true 7 | } 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es5/miscellaneous.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-native-reassign": 2, 4 | "no-negated-in-lhs": 2, 5 | "no-reserved-keys": 0, 6 | "no-spaced-func": 2 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | }, 5 | "include":[ 6 | "modules/*/src" 7 | ], 8 | "references": [ 9 | {"path": "modules/dev-tools"} 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/index.ts: -------------------------------------------------------------------------------- 1 | // JS Tool Configurations 2 | export {getBabelConfig} from './get-babel-config.js'; 3 | export {getESLintConfig} from './get-eslint-config.js'; 4 | export {getPrettierConfig} from './get-prettier-config.js'; 5 | -------------------------------------------------------------------------------- /.markdownlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "colors": true, 4 | "line-length": false, 5 | "ul-style": {"style": "sublist"}, 6 | "no-duplicate-header": false, 7 | "no-inline-html": false, 8 | "no-hard-tabs": false, 9 | "whitespace": false 10 | } 11 | -------------------------------------------------------------------------------- /website/src/home.md: -------------------------------------------------------------------------------- 1 | ## Uber's open source documentation system 2 | 3 | - ![react](images/icon-react.svg) Designed for React 4 | - ![customizable](images/icon-custom.svg) Highly customizable 5 | - ![production-ready](images/icon-target.svg) Totally ready for production 6 | -------------------------------------------------------------------------------- /modules/dev-tools/test/lib/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'tape-promise/tape'; 2 | // @ts-expect-error Aliased import 3 | import {shallowMerge} from 'ocular-dev-tools/utils/utils'; 4 | 5 | test('dev-tools#utils', (t) => { 6 | t.equals(typeof shallowMerge, 'function'); 7 | 8 | t.end(); 9 | }); 10 | -------------------------------------------------------------------------------- /examples/dev-tools/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const {getESLintConfig} = require('ocular-dev-tools'); 2 | 3 | const config = getESLintConfig({react: '16.8.2'}); 4 | 5 | // Make any changes to default config here 6 | 7 | // Uncomment to log the eslint config 8 | // console.debug(config); 9 | 10 | module.exports = config; 11 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/shell.js: -------------------------------------------------------------------------------- 1 | import {execSync} from 'child_process'; 2 | 3 | export function execShellCommand(command, args = []) { 4 | try { 5 | execSync(`${command} ${args.join(' ')}`, { 6 | stdio: 'inherit' 7 | }); 8 | } catch (err) { 9 | process.exit(err.status); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/dev-tools/.prettierrc.js: -------------------------------------------------------------------------------- 1 | const {getPrettierConfig} = require('ocular-dev-tools'); 2 | 3 | const config = getPrettierConfig({react: '16.8.2'}); 4 | 5 | // Make any changes to default config here 6 | 7 | // Uncomment to log the eslint config 8 | // console.debug(config); 9 | 10 | module.exports = config; 11 | -------------------------------------------------------------------------------- /examples/dev-tools/babel.config.js: -------------------------------------------------------------------------------- 1 | const {getBabelConfig} = require('ocular-dev-tools'); 2 | 3 | module.exports = (api) => { 4 | const config = getBabelConfig(api, {react: true}); 5 | 6 | // Make any changes to default config here 7 | 8 | // Uncomment to log the config 9 | // console.debug(config); 10 | 11 | return config; 12 | }; 13 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/lint.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import {execShellCommand} from './shell.js'; 4 | import {join} from 'path'; 5 | 6 | const scriptDir = new URL(import.meta.url).pathname; 7 | // Runs the bash script and forward the arguments, exiting with the same code 8 | execShellCommand(join(scriptDir, '../lint.sh'), process.argv.slice(2)); 9 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/test.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import {execShellCommand} from './shell.js'; 4 | import {join} from 'path'; 5 | 6 | const scriptDir = new URL(import.meta.url).pathname; 7 | // Runs the bash script and forward the arguments, exiting with the same code 8 | execShellCommand(join(scriptDir, '../test.sh'), process.argv.slice(2)); 9 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/build.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import {execShellCommand} from './shell.js'; 4 | import {join} from 'path'; 5 | 6 | const scriptDir = new URL(import.meta.url).pathname; 7 | // Runs the bash script and forward the arguments, exiting with the same code 8 | execShellCommand(join(scriptDir, '../build.sh'), process.argv.slice(2)); 9 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/clean.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import {execShellCommand} from './shell.js'; 4 | import {join} from 'path'; 5 | 6 | const scriptDir = new URL(import.meta.url).pathname; 7 | // Runs the bash script and forward the arguments, exiting with the same code 8 | execShellCommand(join(scriptDir, '../clean.sh'), process.argv.slice(2)); 9 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/metrics.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import {execShellCommand} from './shell.js'; 4 | import {join} from 'path'; 5 | 6 | const scriptDir = new URL(import.meta.url).pathname; 7 | // Runs the bash script and forward the arguments, exiting with the same code 8 | execShellCommand(join(scriptDir, '../metrics.sh'), process.argv.slice(2)); 9 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/publish.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import {execShellCommand} from './shell.js'; 4 | import {join} from 'path'; 5 | 6 | const scriptDir = new URL(import.meta.url).pathname; 7 | // Runs the bash script and forward the arguments, exiting with the same code 8 | execShellCommand(join(scriptDir, '../publish.sh'), process.argv.slice(2)); 9 | -------------------------------------------------------------------------------- /modules/dev-tools/test/index.ts: -------------------------------------------------------------------------------- 1 | import './lib/utils.spec'; 2 | import './lib/configuration.spec'; 3 | 4 | import './ts-plugins/ts-transform-version-inline.spec'; 5 | import './ts-plugins/ts-transform-append-extension.spec'; 6 | import './ts-plugins/ts-transform-remove-glsl-comments/index.spec'; 7 | import './ts-plugins/ts-transform-inline-webgl-constants.spec'; 8 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/bootstrap.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import {execShellCommand} from './shell.js'; 4 | import {join} from 'path'; 5 | 6 | const scriptDir = new URL(import.meta.url).pathname; 7 | // Runs the bash script and forward the arguments, exiting with the same code 8 | execShellCommand(join(scriptDir, '../bootstrap.sh'), process.argv.slice(2)); 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | 4 | .idea/ 5 | yarn-error.log 6 | .DS_Store 7 | .vscode/ 8 | website/dist 9 | website/.DS_Store 10 | website/node_modules 11 | website/yarn-error.log 12 | 13 | package-lock.json 14 | 15 | website-test/* 16 | 17 | .reify-cache 18 | modules/dev-tools/.alias.json 19 | coverage/ 20 | .nyc_output/ 21 | tsconfig.tsbuildinfo 22 | -------------------------------------------------------------------------------- /modules/dev-tools/templates/.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "all": true, 3 | "sourceMap": false, 4 | "instrument": true, 5 | "include": [ 6 | "src/**/*.+(js|jsx|cjs|mjs|ts|tsx)", 7 | "modules/**/src/**/*.+(js|jsx|cjs|mjs|ts|tsx)" 8 | ], 9 | "exclude": [ 10 | "**/deprecated", 11 | "**/wip", 12 | "**/*.spec.+(js|ts)", 13 | "**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/cli/ocular-lint.md: -------------------------------------------------------------------------------- 1 | # ocular-lint 2 | 3 | Run eslint & prettier on the code base. 4 | 5 | ```bash 6 | ocular-lint [mode] 7 | ``` 8 | 9 | ## Modes 10 | 11 | - `full` (default) - run on all files. 12 | - `pre-commit` - only run on changed files since the last commit. 13 | - `fix` - run prettier and eslint --fix on all files. 14 | 15 | ## Configuration 16 | 17 | [Configurations](#ocular-dev-tools-1): `lint` 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ocular 2 | 3 | Ocular is a monorepo for development tools primarily designed for building github-based javascript frameworks. 4 | 5 | It currently contains: 6 | 7 | - `gatsby-theme-ocular` - A documentation generator packaged as a pluggable theme for gatsbyjs documentation generation system. 8 | - `ocular-dev-tools` - A set tools that packages up extensive installation and configuration of babel, webpack, lint, prettier and other state-of-the art JS build tools. 9 | -------------------------------------------------------------------------------- /examples/dev-tools/ocular-dev-tools.config.js: -------------------------------------------------------------------------------- 1 | const {resolve} = require('path'); 2 | 3 | module.exports = { 4 | lint: { 5 | paths: ['./src'], 6 | extensions: ['js'] 7 | }, 8 | 9 | aliases: { 10 | test: resolve(__dirname, 'test') 11 | }, 12 | 13 | entry: { 14 | test: 'test/node.js', 15 | 'test-browser': 'test/browser.js', 16 | bench: 'test/bench/node.js', 17 | 'bench-browser': 'test/bench/browser.js', 18 | size: 'test/size/import-nothing.js' 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/api-reference/get-prettier-config.md: -------------------------------------------------------------------------------- 1 | # getPrettierConfig 2 | 3 | Get `ocular-dev-tools` default prettier config. 4 | 5 | ## Usage 6 | 7 | ```js 8 | // .prettierrc.js 9 | const {getPrettierConfig} = requre('ocular-dev-tools/configuration'); 10 | 11 | modules.export = getPrettierConfig({ 12 | /** This will be deep merged with the default config */ 13 | overrides: { 14 | // custom config 15 | }, 16 | /** Print full config JSON for inspection */ 17 | debug: true 18 | }); 19 | ``` 20 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-2-expected.ts: -------------------------------------------------------------------------------- 1 | const glsl = (x) => `${x}`; 2 | export default { 3 | name: 'shader-module', 4 | getUniforms: () => ({ 5 | useFloatColors: false 6 | }), 7 | inject: { 8 | 'vs:DECKGL_FILTER_COLOR': ` 9 | picking_setPickingColor(geometry.pickingColor); 10 | `, 11 | 'fs:DECKGL_FILTER_COLOR': { 12 | order: 99, 13 | injection: ` 14 | color = picking_filterHighlightColor(color); 15 | color = picking_filterPickingColor(color); 16 | ` 17 | } 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | clean() { 6 | if [ -z "$1" ]; then 7 | (set -x; rm -fr dist && mkdir -p dist) 8 | elif [ "$1" = "all" ]; then 9 | (set -x; rm -fr dist) 10 | else 11 | echo -e "\033[91mUnknown option $1. ocular-clean [all]\033[0m" 12 | exit 1 13 | fi 14 | } 15 | 16 | if [ -d "modules" ]; then 17 | # Monorepo 18 | cd modules 19 | 20 | for D in *; do ( 21 | cd $D 22 | clean $1 23 | ); done 24 | else 25 | clean $1 26 | fi 27 | 28 | find . -name tsconfig.tsbuildinfo -exec rm {} \; 29 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es5/variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-catch-shadow": 2, 4 | "no-delete-var": 2, 5 | "no-label-var": 2, 6 | "no-shadow": 2, 7 | "no-shadow-restricted-names": 2, 8 | "no-undef-init": 2, 9 | "no-undef": 2, 10 | "no-undefined": 0, 11 | "no-unused-vars": [ 12 | 2, 13 | { 14 | "vars": "all", 15 | "args": "none" 16 | } 17 | ], 18 | "no-use-before-define": [ 19 | 2, 20 | "nofunc" 21 | ], 22 | "init-declarations": 0 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /modules/dev-tools/templates/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "outDir": "dist", 7 | "declaration": true, 8 | "declarationMap": true, 9 | "sourceMap": true, 10 | "skipLibCheck": true, 11 | "strict": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "lib": [ 16 | "esnext", 17 | "dom" 18 | ] 19 | }, 20 | "include": [ 21 | "src/**/*" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /.ocularrc.js: -------------------------------------------------------------------------------- 1 | /** @typedef {import('ocular-dev-tools').OcularConfig} OcularConfig */ 2 | import {resolve} from 'path'; 3 | 4 | /** @type {OcularConfig} */ 5 | let ocularConfig = { 6 | typescript: { 7 | project: 'tsconfig.build.json' 8 | }, 9 | 10 | babel: false, 11 | 12 | lint: { 13 | paths: ['modules'] 14 | }, 15 | 16 | aliases: { 17 | test: resolve('./test') 18 | }, 19 | 20 | entry: { 21 | test: 'test/node.ts', 22 | 'test-browser': 'test/index.html', 23 | size: 'test/size/import-nothing.js' 24 | } 25 | }; 26 | 27 | export default ocularConfig; 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "esnext", 5 | "jsx": "react", 6 | "strict": true, 7 | "noImplicitAny": false, 8 | "allowJs": true, 9 | "checkJs": false, 10 | "moduleResolution": "node", 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "noEmit": true, 14 | "resolveJsonModule": true, 15 | "baseUrl": ".", 16 | "skipLibCheck": true 17 | }, 18 | "include": [ 19 | "modules", 20 | "test" 21 | ], 22 | "exclude":[ 23 | "node_modules" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /modules/dev-tools/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "noImplicitAny": false, 6 | "allowJs": true, 7 | "checkJs": false, 8 | "declaration": true, 9 | "declarationMap": true, 10 | "moduleResolution": "node", 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "baseUrl": ".", 14 | "rootDir": "src", 15 | "outDir": "dist", 16 | "composite": true, 17 | "skipLibCheck": true, 18 | "strict": true 19 | }, 20 | "include":[ 21 | "src/**/*" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /modules/dev-tools/src/utils/types.ts: -------------------------------------------------------------------------------- 1 | // https://docs.npmjs.com/cli/v10/configuring-npm/package-json 2 | // Only relevant fields are typed 3 | export type PackageJson = { 4 | name: string; 5 | version: string; 6 | type?: 'module' | 'commonjs'; 7 | main?: string; 8 | module?: string; 9 | exports?: { 10 | [path: string]: string | {import?: string; require?: string; type?: string; default?: string}; 11 | }; 12 | dependencies?: {[name: string]: string}; 13 | devDependencies?: {[name: string]: string}; 14 | peerDependencies?: {[name: string]: string}; 15 | [key: string]: unknown; 16 | }; 17 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/get-prettier-config.ts: -------------------------------------------------------------------------------- 1 | import deepMerge from 'deepmerge'; 2 | 3 | const DEFAULT_CONFIG = { 4 | printWidth: 100, 5 | semi: true, 6 | singleQuote: true, 7 | trailingComma: 'none', 8 | bracketSpacing: false 9 | }; 10 | 11 | export function getPrettierConfig(options: {overrides?: any; debug?: boolean} = {}) { 12 | let config = {...DEFAULT_CONFIG}; 13 | if (options.overrides) { 14 | config = deepMerge(config, options.overrides); 15 | } 16 | if (options.debug) { 17 | // eslint-disable-next-line 18 | console.log(config); 19 | } 20 | return config; 21 | } 22 | -------------------------------------------------------------------------------- /examples/dev-tools/src/app.js: -------------------------------------------------------------------------------- 1 | import React, {PureComponent} from 'react'; 2 | import {render} from 'react-dom'; 3 | 4 | export default class App extends PureComponent { 5 | constructor(props) { 6 | super(props); 7 | this.state = {}; 8 | } 9 | 10 | render() { 11 | return ( 12 |
13 |

This is a minimal React example

14 |

Line...

15 |

Line...

16 |

Line...

17 |

Line...

18 |
19 | ); 20 | } 21 | } 22 | 23 | export function renderToDOM(container) { 24 | render(, container); 25 | } 26 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es5/node-js-and-common-js.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-mixed-requires": [ 4 | 2, 5 | false 6 | ], 7 | "no-new-require": 2, 8 | "no-path-concat": 2, 9 | "no-process-env": 2, 10 | "no-process-exit": 2, 11 | "no-restricted-modules": 0, 12 | "no-sync": 0, 13 | "callback-return": [ 14 | 2, 15 | [ 16 | "callback", 17 | "cb", 18 | "next", 19 | "done" 20 | ] 21 | ], 22 | "handle-callback-err": [ 23 | 2, 24 | "^(err|error|anySpecificError)$" 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/cli/ocular-publish.md: -------------------------------------------------------------------------------- 1 | # ocular-publish 2 | 3 | Publish the packages, create git tag and push. 4 | 5 | ## Usage 6 | 7 | This script will usually be mapped to `publish`: 8 | ```bash 9 | yarn publish [mode] [npm-tag] 10 | ``` 11 | 12 | To run it directly 13 | ```bash 14 | npx ocular-publish [mode] [npm-tag] 15 | ``` 16 | 17 | ## mode 18 | 19 | - `beta` - bump pre-release version and publish with beta flag. 20 | - `prod` - bump patch version and publish. 21 | 22 | ## npm-tag 23 | 24 | Custom tag for the release. If not specified, the release is tagged with `beta` if `mode: beta` and `latest` if `mode: prod`. 25 | -------------------------------------------------------------------------------- /modules/dev-tools/test/lib/configuration.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'tape-promise/tape'; 2 | // @ts-expect-error Aliased import 3 | import {getBabelConfig, getESLintConfig, getPrettierConfig} from 'ocular-dev-tools/configuration'; 4 | 5 | test('dev-tools#getConfig', (t) => { 6 | const mockBabelApi = {cache: {using: () => {}}, env: (env) => env}; 7 | 8 | let config = getESLintConfig(); 9 | t.equals(typeof config, 'object'); 10 | 11 | config = getPrettierConfig(); 12 | t.equals(typeof config, 'object'); 13 | 14 | config = getBabelConfig(mockBabelApi); 15 | t.equals(typeof config, 'function'); 16 | 17 | t.end(); 18 | }); 19 | -------------------------------------------------------------------------------- /examples/dev-tools/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | minimal ocular example 6 | 16 | 17 | 18 |
19 | 20 | 21 | 24 | 25 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/api-reference/get-eslint-config.md: -------------------------------------------------------------------------------- 1 | # getEslintConfig 2 | 3 | Create a `ocular-dev-tools` default eslint config. 4 | 5 | ## Usage 6 | 7 | ```js 8 | // .eslintrc.js 9 | const {getESlintConfig} = requre('ocular-dev-tools/configuration'); 10 | 11 | modules.export = getESlintConfig({ 12 | /** Set React version, if any */ 13 | react: '18.0.0', 14 | /** This will be deep merged with the default config */ 15 | overrides: { 16 | parserOptions: { 17 | project: ['./tsconfig.json'] 18 | }, 19 | rules: { 20 | // custom rules 21 | } 22 | }, 23 | /** Print full config JSON for inspection */ 24 | debug: true 25 | }); 26 | ``` 27 | -------------------------------------------------------------------------------- /modules/dev-tools/templates/.eslintrc.gatsby-todo: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb", "prettier"], 3 | "plugins": ["react", "jsx-a11y", "import"], 4 | "rules": { 5 | "react/prefer-stateless-function": "off", 6 | "react/prop-types": "off", 7 | "react/no-danger": "off", 8 | "jsx-a11y/anchor-is-valid": [ "error", { 9 | "components": [ "Link" ], 10 | "specialLink": [ "hrefLeft", "hrefRight", "to" ], 11 | "aspects": [ "noHref", "invalidHref", "preferButton" ] 12 | }], 13 | "no-restricted-syntax": "off", 14 | "no-param-reassign": "off" 15 | }, 16 | "settings": { 17 | "import/core-modules": [] 18 | }, 19 | "env": { 20 | "browser": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es2015/stylistic-issues.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-continue": 2, 4 | "func-style": [ 5 | 2, 6 | "declaration", 7 | { 8 | "allowArrowFunctions": true 9 | } 10 | ], 11 | "lines-around-comment": [ 12 | 0, 13 | { 14 | "beforeBlockComment": true, 15 | "afterBlockComment": false, 16 | "beforeLineComment": false, 17 | "afterLineComment": false, 18 | "allowBlockStart": true, 19 | "allowBlockEnd": true 20 | } 21 | ], 22 | "quote-props": [ 23 | 2, 24 | "as-needed" 25 | ], 26 | "sort-vars": 2, 27 | "wrap-regex": 2 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /modules/dev-tools/src/helpers/cjs-register.cjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Support module alias in CJS mode 3 | */ 4 | const tsConfigPaths = require('tsconfig-paths'); 5 | // @ts-expect-error 6 | const paths = require('../../.alias.json'); 7 | 8 | tsConfigPaths.register({ 9 | baseUrl: '.', 10 | paths: parseModuleAlias(paths) 11 | }); 12 | 13 | /** Convert ocular alias object to TS config paths object */ 14 | function parseModuleAlias(aliases) { 15 | // Cast user config to tsconfig-style paths 16 | const result = {}; 17 | for (const key in aliases) { 18 | const alias = aliases[key]; 19 | result[key] = [alias]; 20 | if (!alias.match(/(\/\*|\.jsx?|\.tsx?|\.cjs)$/)) { 21 | result[`${key}/*`] = [`${alias}/*`]; 22 | } 23 | } 24 | return result; 25 | } 26 | -------------------------------------------------------------------------------- /dev-docs/RFCs/README.md: -------------------------------------------------------------------------------- 1 | # RFCs and Roadmaps (ocular) 2 | 3 | Implementation of non-trivial new features should typically be started off with the creation of an RFC (Request for Comments). 4 | 5 | 6 | ## Roadmaps 7 | 8 | Writeups of directions in major areas of interest 9 | 10 | | Roadmap | Description | 11 | | --- | --- | 12 | | N/A | TBD | 13 | 14 | 15 | ## v1.0 RFCs 16 | 17 | ocular 1.0 will support static page generation based on gatsby: 18 | 19 | | RFC | Author | Status | Description | 20 | | --- | --- | --- | --- | 21 | | [**gatsby-rfc.md) | @jckr/@ibgreen | **Draft** | Port ocular to use `gatsby` and support static content generation. | 22 | 23 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-2.ts: -------------------------------------------------------------------------------- 1 | const glsl = (x: TemplateStringsArray) => `${x}`; 2 | export default { 3 | name: 'shader-module', 4 | getUniforms: () => ({ 5 | useFloatColors: false 6 | }), 7 | inject: { 8 | 'vs:DECKGL_FILTER_COLOR': glsl` 9 | // pickingColor is expected to be populated by this point 10 | picking_setPickingColor(geometry.pickingColor); 11 | `, 12 | 'fs:DECKGL_FILTER_COLOR': { 13 | order: 99, 14 | injection: glsl` 15 | // use highlight color if this fragment belongs to the selected object. 16 | color = picking_filterHighlightColor(color); 17 | 18 | // use picking color if rendering to picking FBO. 19 | color = picking_filterPickingColor(color); 20 | ` 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /examples/dev-tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ocular-examples-dev-tools", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "scripts": { 7 | "bootstrap": "yarn install-fast && ocular-bootstrap", 8 | "install-fast": "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true yarn", 9 | "build": "ocular-clean && ocular-build", 10 | "clean": "ocular-clean", 11 | "cover": "ocular-test cover", 12 | "lint": "ocular-lint", 13 | "test": "ocular-test" 14 | }, 15 | "dependencies": { 16 | "lodash": "^4.17.19", 17 | "prop-types": "^15.7.2", 18 | "react": "^16.3.0", 19 | "react-dom": "^16.3.0", 20 | "react-map-gl": "^4.1.2", 21 | "styled-components": "^4.2.0" 22 | }, 23 | "devDependencies": { 24 | "ocular-dev-tools": "1.0.0-alpha.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | const {getESLintConfig} = require('ocular-dev-tools/configuration'); 2 | 3 | module.exports = getESLintConfig({ 4 | react: '16.8.2', 5 | overrides: { 6 | parserOptions: { 7 | project: ['./tsconfig.json'] 8 | }, 9 | 10 | settings: { 11 | // Ensure eslint finds typescript files 12 | 'import/resolver': { 13 | node: { 14 | extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx'] 15 | } 16 | } 17 | }, 18 | 19 | rules: { 20 | 'import/no-extraneous-dependencies': 0, 21 | 'import/no-unresolved': 0, 22 | 'no-console': 0, 23 | 'no-continue': 0, 24 | 'no-process-env': 0, 25 | 'no-process-exit': 0 26 | }, 27 | 28 | env: { 29 | node: true 30 | }, 31 | 32 | ignorePatterns: ['modules/gatsby-theme-ocular'] 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /modules/dev-tools/src/build-cjs.ts: -------------------------------------------------------------------------------- 1 | import esbuild from 'esbuild'; 2 | import fs from 'fs/promises'; 3 | import {getCJSEntryPoints} from './helpers/get-cjs-entry-points.js'; 4 | import {getCJSExportConfig} from './configuration/get-esbuild-config.js'; 5 | 6 | async function main() { 7 | for (const entry of getCJSEntryPoints()) { 8 | try { 9 | await fs.stat(entry.inputFile); 10 | 11 | const esbuildConfig = await getCJSExportConfig({ 12 | input: entry.inputFile, 13 | output: entry.outputFile 14 | }); 15 | const result = await esbuild.build(esbuildConfig); 16 | if (result.errors.length > 0) { 17 | process.exit(1); 18 | } 19 | } catch { 20 | // File does not exist 21 | console.error(`\x1b[33mCannot find file ${entry.inputFile}\x1b[0m`); 22 | } 23 | } 24 | } 25 | 26 | main(); 27 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ocular-website", 3 | "version": "1.0.0", 4 | "description": "Website for the vis.gl open source documentation system", 5 | "main": "index.js", 6 | "author": "", 7 | "license": "MIT", 8 | "scripts": { 9 | "start": "yarn clean && yarn develop", 10 | "clean": "rm -rf ./.cache ./public", 11 | "develop": "yarn clean && gatsby develop --port=8002", 12 | "build": "yarn clean && gatsby build --prefix-paths", 13 | "serve": "gatsby serve --prefix-paths", 14 | "deploy": "NODE_DEBUG=gh-pages gh-pages -d public" 15 | }, 16 | "dep_comment": "Ensure gatsby-theme-ocular references unpublished version to trigger local workspaces link", 17 | "dependencies": { 18 | "gatsby": "^2.18.0", 19 | "gatsby-theme-ocular": "^1.2.4", 20 | "react": "^16.8.6", 21 | "react-dom": "^16.8.6", 22 | "sharp": "^0.31.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1-expected.ts: -------------------------------------------------------------------------------- 1 | // Constants 2 | const COORDINATE_SYSTEM = { 3 | CARTESIAN: 0, 4 | LNGLAT: 1 5 | }; 6 | const constantDefinitions = Object.keys(COORDINATE_SYSTEM) 7 | .map((key) => `const int COORDINATE_SYSTEM_${key} = ${COORDINATE_SYSTEM[key]};`) 8 | .join('\n'); 9 | // Vertex shader 10 | export const vs = `\ 11 | #version 300 es 12 | ${constantDefinitions} 13 | in vec4 position; 14 | in vec4 color; 15 | uniform mat4 pMatrix; 16 | uniform mat4 mMatrix; 17 | uniform float opacity; 18 | out vec4 vColor; 19 | main() { 20 | gl_Position = pMatrix * mMatrix * position; 21 | vColor = vec4(color, color.a * opacity); 22 | } 23 | `; 24 | // Fragment shader 25 | export const fs = `\ 26 | #version 300 es 27 | in vec4 vColor; 28 | main() { 29 | if (vColor.a == 0.0) { 30 | discard; 31 | } 32 | gl_FragColor = vColor; 33 | } 34 | `; 35 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script to bootstrap repo for development 3 | 4 | set -e 5 | 6 | # install dependencies 7 | yarn 8 | 9 | # prepare module directories 10 | PACKAGE_DIR=`pwd` 11 | ROOT_NODE_MODULES_DIR=$PACKAGE_DIR/node_modules 12 | 13 | if [ -d "modules" ]; then 14 | # monorepo 15 | cd modules 16 | for D in *; do ( 17 | [ -d $D ] 18 | cd $D 19 | 20 | # create symlink to dev dependencies at root 21 | # this is a bug of yarn: https://github.com/yarnpkg/yarn/issues/4964 22 | # TODO - remove when fixed 23 | mkdir -p node_modules 24 | rm -rf ./node_modules/.bin 25 | ln -sf $ROOT_NODE_MODULES_DIR/.bin ./node_modules 26 | ); done 27 | 28 | cd $PACKAGE_DIR 29 | else 30 | packageName=`node -e "console.log(require('./package.json').name)"` 31 | yarn link 32 | yarn link $packageName 33 | fi 34 | 35 | # build the submodules 36 | npm run build 37 | -------------------------------------------------------------------------------- /docs/wip/gatsby-theme-ocular/upgrade-guide.md: -------------------------------------------------------------------------------- 1 | # Upgrade Guide 2 | 3 | 4 | ## gatsby-theme-ocular 5 | 6 | ### Upgrading from v1.1 to v1.2 7 | 8 | Breaking changes: 9 | - INDEX_PAGE_URL 10 | 11 | ### Upgrading from ocular-gatsby to gatsby-theme-ocular 12 | 13 | Your website needs to update its `gatsby-config.js` and `gatsby-node.js` in the root, and unless you have added additional code, you can remove your `gatsby-browser.js` and `gatsby-ssr.js` as the default implementations can now be supplied by `gatsby-theme-ocular`. 14 | 15 | `gatsby-config.js`: 16 | ```js 17 | const ocularConfig = require('./ocular-config'); 18 | 19 | module.exports = { 20 | plugins: [{resolve: `gatsby-theme-ocular`, options: ocularConfig}], 21 | }; 22 | ``` 23 | 24 | `gatsby-node.js`: 25 | ```js 26 | const {setOcularConfig} = require('gatsby-theme-ocular'); 27 | 28 | const ocularConfig = require('./ocular-config'); 29 | setOcularConfig(ocularConfig); 30 | ``` -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-jsx/miscellaneous.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "react/jsx-no-undef": 2, 4 | "react/no-unknown-property": 1, 5 | "react/jsx-uses-react": 2, 6 | "react/jsx-uses-vars": 2, 7 | "react/no-did-mount-set-state": 1, 8 | "react/no-did-update-set-state": 1, 9 | "react/prop-types": 0, 10 | "react/react-in-jsx-scope": 2, 11 | "react/self-closing-comp": 2, 12 | "react/sort-comp": 1, 13 | "react/jsx-wrap-multilines": 2, 14 | "react/display-name": 1, 15 | "react/no-danger": 1, 16 | "react/no-deprecated": 1, 17 | "react/no-direct-mutation-state": 1, 18 | "react/jsx-indent": [ 19 | 1, 20 | 2 21 | ], 22 | "react/jsx-no-target-blank": 1, 23 | "react/forbid-prop-types": [ 24 | 1, 25 | { 26 | "forbid": [ 27 | "any", 28 | "array" 29 | ] 30 | } 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es2015/ecmascript-6.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-class-assign": 2, 4 | "arrow-spacing": [ 5 | 1, 6 | { 7 | "before": true, 8 | "after": true 9 | } 10 | ], 11 | "no-const-assign": 2, 12 | "no-dupe-class-members": 2, 13 | "no-this-before-super": 2, 14 | "no-var": 2, 15 | "prefer-arrow-callback": 0, 16 | "prefer-const": 2, 17 | "prefer-spread": 2, 18 | "prefer-template": 2, 19 | "arrow-parens": 0, 20 | "arrow-spacing": [ 21 | 2, 22 | { 23 | "before": true, 24 | "after": true 25 | } 26 | ], 27 | "constructor-super": 2, 28 | "generator-star-spacing": [ 29 | 2, 30 | { 31 | "before": false, 32 | "after": true 33 | } 34 | ], 35 | "object-shorthand": [ 36 | 2, 37 | "always" 38 | ], 39 | "require-yield": 2 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /modules/dev-tools/src/helpers/get-config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Used by command line scripts to print a field from the local ocular config. 3 | Path is period separated. 4 | Example: 5 | $ node get-config.js ".babel.configPath" 6 | */ 7 | import {getOcularConfig, MaterializedOcularConfig} from './get-ocular-config.js'; 8 | 9 | let ocularConfig: MaterializedOcularConfig; 10 | try { 11 | ocularConfig = await getOcularConfig(); 12 | } catch (ex) { 13 | console.error('Error resolving ocular config'); 14 | console.error(ex); 15 | process.exit(1); 16 | } 17 | 18 | const configPath = process.argv[2] || ''; 19 | 20 | let config: any = ocularConfig; 21 | 22 | configPath 23 | .split('.') 24 | .filter(Boolean) 25 | .forEach((path) => { 26 | config = config ? config[path] : undefined; 27 | }); 28 | 29 | if (config === undefined) { 30 | config = ''; 31 | } 32 | 33 | if (Array.isArray(config)) { 34 | config = config.join(','); 35 | } 36 | 37 | console.log(config); 38 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/bundle.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import esbuild from 'esbuild'; 4 | import {getBundleConfig} from '../dist/configuration/get-esbuild-config.js'; 5 | 6 | // Parse command line arguments 7 | let entryPoint; 8 | const env = {}; 9 | 10 | for (let i = 1; i < process.argv.length; i++) { 11 | const arg = process.argv[i]; 12 | if (arg.startsWith('--')) { 13 | const tokens = arg.slice(2).split('='); 14 | env[tokens[0]] = tokens[1] === undefined ? true : tokens[1]; 15 | } else if (!entryPoint && arg.match(/\.(js|ts|cjs|mjs|jsx|tsx)$/)) { 16 | entryPoint = arg; 17 | } 18 | } 19 | 20 | const buildConfig = await getBundleConfig({ 21 | ...env, 22 | input: entryPoint 23 | }); 24 | 25 | if (env.watch) { 26 | buildConfig.watch = true; 27 | await esbuild.build(buildConfig); 28 | /* eslint-disable no-console */ 29 | console.log('watching...'); 30 | } else { 31 | const result = await esbuild.build(buildConfig); 32 | if (result.errors.length > 0) { 33 | process.exit(1); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1.ts: -------------------------------------------------------------------------------- 1 | // Constants 2 | const COORDINATE_SYSTEM = { 3 | CARTESIAN: 0, 4 | LNGLAT: 1 5 | }; 6 | const constantDefinitions = Object.keys(COORDINATE_SYSTEM) 7 | .map((key) => `const int COORDINATE_SYSTEM_${key} = ${COORDINATE_SYSTEM[key]};`) 8 | .join('\n'); 9 | // Vertex shader 10 | export const vs = `\ 11 | #version 300 es 12 | ${constantDefinitions} 13 | 14 | in vec4 position; 15 | in vec4 color; 16 | 17 | uniform mat4 pMatrix; // Projection matrix 18 | uniform mat4 mMatrix; // Model matrix 19 | uniform float opacity; 20 | 21 | out vec4 vColor; 22 | 23 | main() { 24 | gl_Position = pMatrix * mMatrix * position; 25 | vColor = vec4(color, /* inline comment */ color.a * opacity); 26 | } 27 | `; 28 | // Fragment shader 29 | export const fs = `\ 30 | #version 300 es 31 | 32 | in vec4 vColor; 33 | 34 | main() { 35 | if (vColor.a == 0.0) { 36 | /* 37 | Remove transparent fragment 38 | */ 39 | discard; 40 | } 41 | gl_FragColor = vColor; 42 | } 43 | `; 44 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | # On every pull request, but only on push to master 4 | on: 5 | push: 6 | branches: 7 | - master 8 | pull_request: 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | node-version: [18] 16 | 17 | steps: 18 | - uses: actions/checkout@v2.1.1 19 | 20 | - uses: c-hive/gha-yarn-cache@v1 21 | 22 | - name: Set up Node ${{ matrix.node-version }} 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | 27 | - name: Bootstrap 28 | run: | 29 | yarn bootstrap 30 | 31 | - name: Run tests 32 | run: | 33 | npm run lint 34 | npm run test cover 35 | npm run cover 36 | 37 | - name: Coveralls 38 | if: matrix.node-version == 12 39 | uses: coverallsapp/github-action@master 40 | with: 41 | github-token: ${{ secrets.GITHUB_TOKEN }} 42 | path-to-lcov: ${{ github.workspace }}/coverage/lcov.info -------------------------------------------------------------------------------- /examples/dev-tools/dist/es5/app.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../src/app.js"],"names":["App","props","state","color","PureComponent","renderToDOM","container"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;;;;;IAEqBA,G;;;;;AACnB,eAAYC,KAAZ,EAAmB;AAAA;;AAAA;AACjB,8BAAMA,KAAN;AACA,UAAKC,KAAL,GAAa,EAAb;AAFiB;AAGlB;;;;WAED,kBAAS;AACP,aACE;AAAK,QAAA,KAAK,EAAE;AAACC,UAAAA,KAAK,EAAE;AAAR;AAAZ,SACE,0EADF,EAEE,kDAFF,EAGE,kDAHF,EAIE,kDAJF,EAKE,kDALF,CADF;AASD;;;EAhB8BC,oB;;;;AAmB1B,SAASC,WAAT,CAAqBC,SAArB,EAAgC;AACrC,wBAAO,6BAAC,GAAD,OAAP,EAAgBA,SAAhB;AACD","sourcesContent":["import React, {PureComponent} from 'react';\nimport {render} from 'react-dom';\n\nexport default class App extends PureComponent {\n constructor(props) {\n super(props);\n this.state = {};\n }\n\n render() {\n return (\n
\n

This is a minimal React example

\n

Line...

\n

Line...

\n

Line...

\n

Line...

\n
\n );\n }\n}\n\nexport function renderToDOM(container) {\n render(, container);\n}\n"],"file":"app.js"} -------------------------------------------------------------------------------- /modules/dev-tools/docs/api-reference/get-babel-config.md: -------------------------------------------------------------------------------- 1 | # getBabelConfig 2 | 3 | Create a `ocular-dev-tools` default babel config. 4 | 5 | ## Usage 6 | 7 | ```js 8 | // babel.config.js 9 | const {getBabelConfig} = require('ocular-dev-tools/configuration'); 10 | 11 | module.exports = getBabelConfig({ 12 | /** Enable React preset */ 13 | react: true, 14 | /** This will be deep merged with the default config */ 15 | overrides: { 16 | plugins: [ 17 | // custom plugins 18 | ] 19 | }, 20 | /** Print full config JSON for inspection */ 21 | debug: true 22 | }); 23 | ``` 24 | 25 | ## Environments 26 | 27 | The following environments may be used by various commands: 28 | 29 | - `es5` - default commonjs entry point for non-ESM module used by `ocular-build` 30 | - `esm` - default ESM entry point for non-ESM module used by `ocular-build` 31 | - `esm-strict` - default ESM entry point for ESM module used by `ocular-build` 32 | - `bundle` - production bundle settings used by `ocular-bundle` 33 | - `bundle-dev` - developer bundle settings used by `ocular-bundle --env=dev` 34 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | ### Node ### 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | *.pid.lock 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # nyc test coverage 20 | .nyc_output 21 | 22 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 23 | .grunt 24 | 25 | # node-waf configuration 26 | .lock-wscript 27 | 28 | # Compiled binary addons (http://nodejs.org/api/addons.html) 29 | build/Release 30 | 31 | # Dependency directories 32 | node_modules 33 | jspm_packages 34 | 35 | # Optional npm cache directory 36 | .npm 37 | 38 | # Optional eslint cache 39 | .eslintcache 40 | 41 | # Optional REPL history 42 | .node_repl_history 43 | 44 | # Output of 'npm pack' 45 | *.tgz 46 | 47 | # Yarn Integrity file 48 | .yarn-integrity 49 | 50 | 51 | # Build Files 52 | public/ 53 | .cache/ 54 | 55 | # Gatsby context 56 | .gatsby-context.js 57 | 58 | # Bundle stats 59 | bundle-stats.json 60 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/vite.config.js: -------------------------------------------------------------------------------- 1 | import {defineConfig} from 'vite'; 2 | import {getOcularConfig} from '../helpers/get-ocular-config.js'; 3 | import {NodeGlobalsPolyfillPlugin} from '@esbuild-plugins/node-globals-polyfill'; 4 | import {NodeModulesPolyfillPlugin} from '@esbuild-plugins/node-modules-polyfill'; 5 | 6 | export default defineConfig(async ({mode}) => { 7 | const ocularConfig = await getOcularConfig({aliasMode: 'browser'}); 8 | const entryPoint = ocularConfig.entry[`${mode}-browser`]; 9 | 10 | return { 11 | optimizeDeps: { 12 | // Disable crawling the whole repo 13 | entries: [entryPoint], 14 | // Polyfill for Node environment (required by tape-promise) 15 | esbuildOptions: { 16 | define: { 17 | global: 'globalThis', 18 | __dirname: '"."' 19 | }, 20 | plugins: [ 21 | NodeGlobalsPolyfillPlugin({ 22 | process: true 23 | }), 24 | NodeModulesPolyfillPlugin() 25 | ] 26 | } 27 | }, 28 | resolve: { 29 | alias: ocularConfig.aliases 30 | } 31 | }; 32 | }); 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Uber Technologies, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ocular-monorepo", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "workspaces": [ 7 | "modules/dev-tools" 8 | ], 9 | "scripts": { 10 | "bootstrap": "yarn install-fast && ocular-bootstrap", 11 | "install-fast": "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true yarn", 12 | "build": "ocular-clean && tspc -b modules/dev-tools/tsconfig.json && ocular-build", 13 | "clean": "ocular-clean", 14 | "cover": "ocular-test cover", 15 | "lint": "ocular-lint", 16 | "test": "ocular-test node", 17 | "publish-devtools-beta": "(cd modules/dev-tools; npm run publish-beta)", 18 | "publish-devtools-prod": "(cd modules/dev-tools; npm run publish-prod)", 19 | "pre-commit": "yarn lint", 20 | "pre-push": "ocular-test fast" 21 | }, 22 | "devDependencies": { 23 | "@babel/plugin-syntax-import-assertions": "^7.20.0", 24 | "@luma.gl/constants": "^9.0.0-beta", 25 | "pre-commit": "^1.2.2", 26 | "pre-push": "^0.1.1", 27 | "ts-morph": "^21.0.0" 28 | }, 29 | "pre-commit": "pre-commit", 30 | "pre-push": "pre-push", 31 | "dependencies": {} 32 | } 33 | -------------------------------------------------------------------------------- /examples/dev-tools/dist/esm/app.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../src/app.js"],"names":["React","PureComponent","render","App","props","state","color","renderToDOM","container"],"mappings":";;;;;;;;;;AAAA,OAAOA,KAAP,IAAeC,aAAf,QAAmC,OAAnC;AACA,SAAQC,MAAR,QAAqB,WAArB;;IAEqBC,G;;;;;AACnB,eAAYC,KAAZ,EAAmB;AAAA;;AAAA;;AACjB,8BAAMA,KAAN;AACA,UAAKC,KAAL,GAAa,EAAb;AAFiB;AAGlB;;;;WAED,kBAAS;AACP,aACE;AAAK,QAAA,KAAK,EAAE;AAACC,UAAAA,KAAK,EAAE;AAAR;AAAZ,SACE,iEADF,EAEE,yCAFF,EAGE,yCAHF,EAIE,yCAJF,EAKE,yCALF,CADF;AASD;;;;EAhB8BL,a;;SAAZE,G;AAmBrB,OAAO,SAASI,WAAT,CAAqBC,SAArB,EAAgC;AACrCN,EAAAA,MAAM,CAAC,oBAAC,GAAD,OAAD,EAAUM,SAAV,CAAN;AACD","sourcesContent":["import React, {PureComponent} from 'react';\nimport {render} from 'react-dom';\n\nexport default class App extends PureComponent {\n constructor(props) {\n super(props);\n this.state = {};\n }\n\n render() {\n return (\n
\n

This is a minimal React example

\n

Line...

\n

Line...

\n

Line...

\n

Line...

\n
\n );\n }\n}\n\nexport function renderToDOM(container) {\n render(, container);\n}\n"],"file":"app.js"} -------------------------------------------------------------------------------- /modules/dev-tools/docs/cli/ocular-bump.md: -------------------------------------------------------------------------------- 1 | # ocular-bump 2 | 3 | ```bash 4 | ocular-bump [package_name] 5 | ocular-bump [package_name]=beta 6 | ocular-bump [package_name]=[target_version] 7 | ``` 8 | This script helps replace packages with specified version inside a repo. Replace the dependency with the target version of all the `package.json` files under directories `root`. 9 | 10 | For monerepos, you can use the package name to bump all the modules to the corresponding version. 11 | 12 | Given a `package-name`, `modules` to bump are the results from `npm search [package-name]` 13 | 14 | - deck.gl: `ocular-bump deck.gl` or `ocular-bump deck.gl=beta` 15 | - luma.gl: `ocular-bump luma.gl` or `ocular-bump luma.gl=beta` 16 | - math.gl: `ocular-bump math.gl` or `ocular-bump math.gl=beta` 17 | - probe.gl: `ocular-bump probe.gl` or `ocular-bump probe.gl=beta` 18 | 19 | ## Examples 20 | 21 | ```shell script 22 | 23 | # deck.gl, luma.gl, math.gl, probe.gl 24 | ocular-bump luma.gl # default to latest 25 | ocular-bump luma.gl=latest 26 | ocular-bump deck.gl=beta luma.gl=beta 27 | ocular-bump math.gl=3.0.0 28 | 29 | # other package 30 | ocular-bump babel-loader # =latest, =beta, =1.0.0 31 | ``` 32 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/cli/ocular-test.md: -------------------------------------------------------------------------------- 1 | # ocular-test 2 | 3 | Run tests. 4 | 5 | ## Usage 6 | 7 | This script will usually be mapped to `test`: 8 | ```bash 9 | yarn test [mode] 10 | ``` 11 | 12 | To run it directly 13 | ```bash 14 | npx ocular-test [mode] 15 | ``` 16 | 17 | ## Modes 18 | 19 | - `full` (default) - run lint, unit tests in node and headless browser 20 | - `fast` - run lint in pre-commit mode, unit tests in node 21 | - `dist` - run unit tests with transpiled (es5) code 22 | - `cover` - run unit tests and generate coverage report 23 | - `ci` - run lint, coverage, metrics and unit tests in headless browser 24 | - `node` - run unit tests in node 25 | - `node-debug` - run unit tests in node debugger 26 | - `browser` - run unit tests in browser (kept open for debugging) 27 | - `browser-headless` - run unit tests in headless browser 28 | - `bench` - run benchmarks in node 29 | - `bench-browser` - run benchmarks in browser (kept open for debugging) 30 | - other - custom mode: 31 | + If -browser is in the mode name, run in browser, otherwise run in node 32 | + If -browser-headless is in the mode name, run in headless browser 33 | + The rest of the name is used to look up the entry point from the entry config. 34 | 35 | ## Configuration 36 | 37 | [Configurations](#ocular-dev-tools-1): `aliases`, `entry` 38 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/ts-transform-version-inline.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'tape-promise/tape'; 2 | import {transpile, assertSourceEqual} from './test-transformer.js'; 3 | // @ts-expect-error Aliased import, remapped to valid path in esm-loader 4 | import versionInline from 'ocular-dev-tools/ts-plugins/ts-transform-version-inline'; 5 | 6 | const testCases = [ 7 | { 8 | title: 'default identifier replaced', 9 | config: {}, 10 | input: 'const version: string = __VERSION__;', 11 | output: 'const version = "0.0.0";' 12 | }, 13 | { 14 | title: 'no matching identifier', 15 | config: {}, 16 | input: 'const version: string = deck.__VERSION__;', 17 | output: 'const version = deck.__VERSION__;' 18 | }, 19 | { 20 | title: 'custom identifier replaced', 21 | config: {identifier: '__package_version'}, 22 | input: 'const version: string = __package_version;', 23 | output: 'const version = "0.0.0";' 24 | } 25 | ]; 26 | 27 | test('ts-transform-version-inline', (t) => { 28 | for (const testCase of testCases) { 29 | const result = transpile({ 30 | source: testCase.input, 31 | transformer: versionInline, 32 | config: testCase.config 33 | }); 34 | 35 | t.is(assertSourceEqual(result, testCase.output), true, testCase.title); 36 | } 37 | 38 | t.end(); 39 | }); 40 | -------------------------------------------------------------------------------- /modules/dev-tools/src/helpers/get-cjs-entry-points.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import type {PackageJson} from '../utils/types.js'; 3 | 4 | export function getCJSEntryPoints(): { 5 | inputFile: string; 6 | outputFile: string; 7 | }[] { 8 | const packageInfo = JSON.parse(fs.readFileSync('package.json', 'utf-8')) as PackageJson; 9 | 10 | if (packageInfo.exports) { 11 | const result: { 12 | inputFile: string; 13 | outputFile: string; 14 | }[] = []; 15 | for (const key in packageInfo.exports) { 16 | const entry = packageInfo.exports[key]; 17 | let outputFile: string = ''; 18 | if (typeof entry === 'string') { 19 | outputFile = entry; 20 | } else if (entry.require) { 21 | outputFile = entry.require; 22 | } else if (entry.default) { 23 | outputFile = entry.default; 24 | } 25 | if (outputFile && outputFile.endsWith('.cjs')) { 26 | let inputFile: string; 27 | 28 | if (typeof entry === 'object' && entry.import) { 29 | inputFile = entry.import; 30 | } else { 31 | inputFile = outputFile.replace('.cjs', '.js'); 32 | } 33 | result.push({inputFile, outputFile}); 34 | } 35 | } 36 | return result; 37 | } 38 | 39 | // Default entry 40 | return [{inputFile: './dist/index.js', outputFile: './dist.index.cjs'}]; 41 | } 42 | -------------------------------------------------------------------------------- /modules/dev-tools/src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import {resolve, dirname} from 'path'; 3 | import {fileURLToPath} from 'node:url'; 4 | import {execSync} from 'child_process'; 5 | 6 | export function execShellCommand(command: string, args: string[] = []) { 7 | try { 8 | execSync(`${command} ${args.join(' ')}`, { 9 | stdio: 'inherit' 10 | }); 11 | } catch (err: unknown) { 12 | process.exit((err as any).status); 13 | } 14 | } 15 | 16 | /** Returns the path to the root directory of ocular-dev-tools */ 17 | export const ocularRoot: string = (function () { 18 | let dir; 19 | try { 20 | dir = __dirname; 21 | } catch { 22 | dir = dirname(fileURLToPath(import.meta.url)); 23 | } 24 | return resolve(dir, '../..'); 25 | })(); 26 | 27 | export function shallowMerge(base: T, override: any): T { 28 | for (const key in override) { 29 | if (base[key] && typeof base[key] === 'object') { 30 | Object.assign(base[key], override[key]); 31 | } else { 32 | base[key] = override[key]; 33 | } 34 | } 35 | return base; 36 | } 37 | 38 | /** Given a list of paths, return the first one that exists */ 39 | export function getValidPath(...resolveOrder: string[]): string | null { 40 | for (const path of resolveOrder) { 41 | if (fs.existsSync(path)) { 42 | return path; 43 | } 44 | } 45 | return null; 46 | } 47 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/ts-transform-inline-webgl-constants.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'tape-promise/tape'; 2 | import {transpile, assertSourceEqual} from './test-transformer.js'; 3 | // @ts-expect-error Aliased import, remapped to valid path in esm-loader 4 | import inlineConstants from 'ocular-dev-tools/ts-plugins/ts-transform-inline-webgl-constants'; 5 | 6 | const testCases = [ 7 | { 8 | title: 'drop GL import', 9 | input: `\ 10 | device.setParametersWebGL({ 11 | blendFunc: [GL.ONE, GL.ONE_MINUS_DST_COLOR, GL.SRC_ALPHA, GL.DST_ALPHA] 12 | }); 13 | `, 14 | output: `\ 15 | device.setParametersWebGL({ 16 | blendFunc: [1, 775, 770, 772] 17 | }); 18 | ` 19 | }, 20 | { 21 | title: 'gl constants replaced', 22 | input: `gl.getParameter(gl.CULL_FACE_MODE);`, 23 | output: `gl.getParameter(2885);` 24 | }, 25 | { 26 | title: 'static property replaced', 27 | input: `console.log(GL['TRIANGLES']);`, 28 | output: `console.log(4);` 29 | }, 30 | { 31 | title: 'dynamic property not replaced', 32 | input: `\ 33 | const name = 'TRIANGLES'; 34 | console.log(GL[name]); 35 | `, 36 | output: `\ 37 | const name = 'TRIANGLES'; 38 | console.log(GL[name]); 39 | ` 40 | } 41 | ]; 42 | 43 | test('ts-transform-inline-webgl-constants', (t) => { 44 | for (const testCase of testCases) { 45 | const result = transpile({ 46 | source: testCase.input, 47 | transformer: inlineConstants, 48 | config: {} 49 | }); 50 | 51 | t.is(assertSourceEqual(result, testCase.output), true, testCase.title); 52 | } 53 | 54 | t.end(); 55 | }); 56 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-jsx/eslintrc.json: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | { 22 | "extends": [ 23 | "../eslint-config-uber-es2015/eslintrc.json", 24 | "./best-practices.json", 25 | "./miscellaneous.json", 26 | "./stylistic-issues.json" 27 | ], 28 | "parserOptions": { 29 | "ecmaFeatures": { 30 | "jsx": true, 31 | "experimentalObjectRestSpread": true 32 | } 33 | }, 34 | "plugins": ["react"] 35 | } 36 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Welcome 2 | 3 | ocular is a set of tools to help build and publish open source frameworks. It contains: 4 | - a `dev-tools` module that installs and provides base configurations for tools like webpack, babel, lerna, eslint prettier etc. 5 | - a `gatsby-theme-ocular` module that contains a markdown to HTML converter to make it easy to build websites. 6 | ## About ocular-dev-tools 7 | 8 | ocular-dev-tools installs a set of configurable development scripts to handle build, test and publish tasks for JavaScript framework repositories. 9 | 10 | While highly configurable ocular-dev-tools is very opinionated in choice of tooling etc, and mainly targets vis.gl frameworks, like deck.gl, luma.gl etc. 11 | 12 | ## About gatsby-theme-ocular 13 | 14 | The vis.gl team needed a system to build documentation websites with the least amount of friction. Our first use case has been the websites for the various visualization projects such as [deck.gl](https://deck.gl) [luma.gl](https://luma.gl) or [loaders.gl](https://loaders.gl). 15 | 16 | We wanted: 17 | - to organize documentation files with a table of contents, navigation and search; 18 | - to have interactive examples; 19 | - to have some control on formatting; 20 | - to generate websites discoverable by search engines; 21 | - to make it easy to publish these websites, especially on github pages; 22 | - to make this experience possible without writing a line of code; 23 | - to provide sensible defaults in terms of navigation and styling; 24 | - but to allow advanced users to overwrite and customize anything they want. 25 | 26 | Happy documenting! 27 | 28 | To find out more, go to [get started](get-started.md) 29 | 30 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es2015/eslintrc.json: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | { 21 | "extends": [ 22 | "./best-practices.json", 23 | "./ecmascript-6.json", 24 | "./miscellaneous.json", 25 | "./stylistic-issues.json", 26 | "../eslint-config-uber-es5/eslintrc.json" 27 | ], 28 | "env": { 29 | "es6": true 30 | }, 31 | "parserOptions": { 32 | "sourceType": "module", 33 | "ecmaFeatures": { 34 | "experimentalObjectRestSpread": true 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/whats-new.md: -------------------------------------------------------------------------------- 1 | # What's New 2 | 3 | `ocular-dev-tools` release details are available in the [CHANGELOG](https://github.com/uber-web/ocular/blob/master/modules/dev-tools/CHANGELOG.md) 4 | 5 | ### v1.0.0 (alpha) 6 | 7 | Release Date: This release is still in development 8 | 9 | #### Command logging 10 | 11 | The various scripts now log the actual commands they issue, making it easier 12 | to see what ocular is doing under the hood. 13 | 14 | ```sh 15 | dev-tools (ib/log-commands *)$ yarn lint fix 16 | yarn run v1.22.5 17 | $ ocular-lint fix 18 | Running prettier in ./src... 19 | + npx prettier --log-level warn --write './src/**/*.js' '*.js' 20 | Running eslint in ./src... 21 | + npx eslint --fix './src/**/*.js' 22 | Lockfile valid. 23 | ✨ Done in 2.15s. 24 | ``` 25 | 26 | #### **Functional entry points** 27 | 28 | Functional entry points to get ocular default configurations for various build tools are now exported. 29 | 30 | ```js 31 | const {getESLintConfig, deepMerge} = require('ocular-dev-tools'); 32 | 33 | const defaultConfig = getESLintConfig({react: '16.8.2'}); 34 | 35 | // Make any changes to default config here 36 | const config = deepMerge(defaultConfig, { 37 | // your overrides 38 | }); 39 | 40 | module.exports = config; 41 | ``` 42 | 43 | ### **Typescript for function entry points** 44 | 45 | The new entry points have JSDoc and typescript definitions. This enables 46 | better checking of arguments and also allows users to see intellisense 47 | information in vscode etc. 48 | 49 | 50 | ### v0.3.0 51 | 52 | Some release details are available in the [CHANGELOG](https://github.com/uber-web/ocular/blob/master/modules/dev-tools/CHANGELOG.md) 53 | 54 | - `ocular-test node-debug` - New mode - starts node debugger 55 | -------------------------------------------------------------------------------- /examples/dev-tools/webpack.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | const getWebpackConfig = require('ocular-dev-tools/config/webpack.config'); 3 | 4 | module.exports = (env = {}) => { 5 | const config = getWebpackConfig(env); 6 | 7 | // Make any changes to default config here 8 | 9 | // Uncomment to debug config 10 | // console.log(JSON.stringify(config, null, 2)); 11 | 12 | return [config]; 13 | }; 14 | 15 | /* 16 | 17 | const COMMON_CONFIG = { 18 | mode: "development", 19 | 20 | entry: { 21 | app: "./app.js" 22 | }, 23 | 24 | output: { 25 | library: "App" 26 | }, 27 | 28 | module: { 29 | rules: [ 30 | { 31 | // Transpile ES6 to ES5 with babel 32 | // Remove if your app does not use JSX or you don't need to support old browsers 33 | test: /\.js$/, 34 | loader: "babel-loader", 35 | exclude: [/node_modules/], 36 | options: { 37 | presets: ["@babel/preset-env", "@babel/preset-react"] 38 | } 39 | } 40 | ] 41 | } 42 | }; 43 | 44 | function addDevConfig(config, env) { 45 | // config = require('../webpack.config.local')(config)(env); 46 | return config; 47 | } 48 | 49 | function addProdConfig(config) { 50 | config.plugins = config.plugins || []; 51 | 52 | return Object.assign(config, { 53 | mode: "production" 54 | }); 55 | } 56 | 57 | module.exports = env => { 58 | env = env || {}; 59 | 60 | let config = COMMON_CONFIG; 61 | 62 | if (env.local) { 63 | config = addDevConfig(config, env); 64 | } 65 | 66 | if (env.prod) { 67 | config = addProdConfig(config); 68 | } 69 | 70 | // Enable to debug config 71 | // console.warn(JSON.stringify(config, null, 2)); 72 | 73 | return config; 74 | }; 75 | */ 76 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es5/eslintrc.json: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | { 22 | "extends": [ 23 | "./best-practices.json", 24 | "./errors.json", 25 | "./miscellaneous.json", 26 | "./node-js-and-common-js.json", 27 | "./strict-mode.json", 28 | "./stylistic-issues.json", 29 | "./variables.json" 30 | ], 31 | "parser": "espree", // TODO: remove? 32 | "env": { 33 | "browser": false, 34 | "node": false, 35 | "amd": false, 36 | "mocha": false, 37 | "jasmine": false, 38 | "es6": false 39 | }, 40 | "globals": { 41 | "__dirname": false, 42 | "__filename": false, 43 | "require": false, 44 | "module": false 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /modules/dev-tools/src/ts-plugins/ts-transform-inline-webgl-constants/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * TypeScript transform to replaces `gl.` or `GL.` references with 3 | * the corresponding WebGL constant value. Requires `@luma.gl/constants` as peer dependency. 4 | * Usage with ts-patch: 5 | { 6 | "plugins": [ 7 | { 8 | "transform": "ocular-dev-tools/ts-transform-inline-webgl-constants" 9 | } 10 | ] 11 | } 12 | */ 13 | import type {Program, TransformationContext, SourceFile, Node, StringLiteral} from 'typescript'; 14 | import type {TransformerExtras, PluginConfig} from 'ts-patch'; 15 | import {GL} from '@luma.gl/constants'; 16 | 17 | export default function (program: Program, pluginConfig: PluginConfig, {ts}: TransformerExtras) { 18 | return (ctx: TransformationContext) => { 19 | const {factory} = ctx; 20 | 21 | function filterLeftIdentifier(node: Node): boolean { 22 | const left = node.getChildAt(0); 23 | return ts.isIdentifier(left) && (left.text === 'GL' || left.text === 'gl'); 24 | } 25 | 26 | return (sourceFile: SourceFile) => { 27 | function visit(node: Node): Node { 28 | if (ts.isPropertyAccessExpression(node) && filterLeftIdentifier(node)) { 29 | const key = node.getChildAt(2); 30 | if (ts.isIdentifier(key) && key.text in GL) { 31 | return factory.createNumericLiteral(GL[key.text]); 32 | } 33 | } 34 | if (ts.isElementAccessExpression(node) && filterLeftIdentifier(node)) { 35 | const key = node.getChildAt(2); 36 | if (ts.isStringLiteral(key) && key.text in GL) { 37 | return factory.createNumericLiteral(GL[key.text]); 38 | } 39 | } 40 | return ts.visitEachChild(node, visit, ctx); 41 | } 42 | return ts.visitNode(sourceFile, visit); 43 | }; 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es5/best-practices.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-alert": 2, 4 | "no-caller": 2, 5 | "no-div-regex": 2, 6 | "no-else-return": 2, 7 | "no-eq-null": 2, 8 | "no-extend-native": 2, 9 | "no-labels": 2, 10 | "no-eval": 2, 11 | "no-extra-bind": 2, 12 | "no-fallthrough": 2, 13 | "no-floating-decimal": 2, 14 | "no-implicit-coercion": 2, 15 | "no-implied-eval": 2, 16 | "no-invalid-this": 2, 17 | "no-iterator": 2, 18 | "no-lone-blocks": 2, 19 | "no-loop-func": 2, 20 | "no-multi-spaces": 2, 21 | "no-multi-str": 2, 22 | "no-new": 2, 23 | "no-new-func": 2, 24 | "no-new-wrappers": 2, 25 | "no-octal": 2, 26 | "no-octal-escape": 2, 27 | "no-param-reassign": 0, 28 | "no-proto": 2, 29 | "no-redeclare": 2, 30 | "no-return-assign": 2, 31 | "no-script-url": 2, 32 | "no-self-compare": 2, 33 | "no-sequences": 2, 34 | "no-throw-literal": 2, 35 | "no-unused-expressions": 2, 36 | "no-useless-call": 2, 37 | "no-void": 1, 38 | "no-warning-comments": [ 39 | 0, 40 | { 41 | "terms": [ 42 | "todo", 43 | "fixme", 44 | "xxx" 45 | ], 46 | "location": "start" 47 | } 48 | ], 49 | "no-with": 2, 50 | "block-scoped-var": 2, 51 | "complexity": [ 52 | 2, 53 | 11 54 | ], 55 | "consistent-return": 2, 56 | "curly": [ 57 | 2, 58 | "all" 59 | ], 60 | "default-case": 2, 61 | "dot-location": [ 62 | 2, 63 | "property" 64 | ], 65 | "dot-notation": [ 66 | 2, 67 | { 68 | "allowKeywords": true 69 | } 70 | ], 71 | "eqeqeq": 2, 72 | "guard-for-in": 2, 73 | "radix": 2, 74 | "vars-on-top": 0, 75 | "wrap-iife": 2, 76 | "yoda": [ 77 | 2, 78 | "never" 79 | ] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Automated tests 3 | 4 | set -e 5 | 6 | BASEDIR=$(dirname "$0") 7 | 8 | MODE=$1 9 | 10 | MODULE_DIR=$(dirname $0)/.. 11 | TEST_SCRIPT=$MODULE_DIR/dist/test.js 12 | 13 | usage() { 14 | # TODO: Add more specific url 15 | open "https://uber-web.github.io/ocular/docs/dev-tools/cli/ocular-test" 16 | } 17 | 18 | run_test_script() { 19 | (set -x; NODE_ENV=test node $TEST_SCRIPT $1) 20 | } 21 | 22 | run_full_test() { 23 | npm run lint 24 | run_test_script node 25 | run_test_script browser-headless 26 | ocular-metrics 27 | } 28 | 29 | case $MODE in 30 | "") 31 | echo "test [ 'full' | 'fast' | 'dist' | 'bench' | 'ci' | 'cover' | 'browser' | 'browser-headless' ]" 32 | echo "Running 'full' test by default" 33 | run_full_test 34 | ;; 35 | 36 | "full") 37 | run_full_test 38 | ;; 39 | 40 | "fast") 41 | ocular-lint pre-commit 42 | run_test_script node 43 | ;; 44 | 45 | "node") 46 | run_test_script $MODE 47 | ;; 48 | 49 | "node-debug") 50 | echo "Open chrome://inspect/#devices to attach debugger." 51 | (set -x; node --inspect-brk $TEST_SCRIPT node) 52 | ;; 53 | 54 | "dist") 55 | run_test_script dist 56 | ;; 57 | 58 | "cover") 59 | run_test_script cover 60 | (set -x; npx c8 report --reporter=lcov) 61 | ;; 62 | 63 | "ci") 64 | # run by Travis CI 65 | npm run lint 66 | run_test_script browser-headless 67 | ocular-test cover 68 | # node test/start.js bench 69 | # ocular-metrics 70 | ;; 71 | 72 | "browser") 73 | run_test_script $MODE 74 | ;; 75 | 76 | "browser-headless") 77 | run_test_script $MODE 78 | ;; 79 | 80 | "bench") 81 | run_test_script $MODE 82 | ;; 83 | 84 | "bench-browser") 85 | run_test_script $MODE 86 | ;; 87 | 88 | *) 89 | # default test 90 | # echo "Error: unknown test mode $MODE" 91 | # usage() 92 | ;; 93 | 94 | esac 95 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/ts-transform-append-extension.spec.ts: -------------------------------------------------------------------------------- 1 | import test from 'tape-promise/tape'; 2 | import {transpile, assertSourceEqual} from './test-transformer.js'; 3 | // @ts-expect-error Aliased import, remapped to valid path in esm-loader 4 | import appendExtension from 'ocular-dev-tools/ts-plugins/ts-transform-append-extension'; 5 | 6 | const input = `\ 7 | export type { TypedArray } from "./types"; 8 | export { add } from "./math/add"; 9 | import vs from "../shaders/vs.glsl"; 10 | import { Shader } from "@luma.gl/core"; 11 | export { vs, Shader };`; 12 | 13 | const testCases = [ 14 | { 15 | title: 'add default extension to js imports', 16 | config: {after: true}, 17 | output: `\ 18 | export { add } from "./math/add.js"; 19 | import vs from "../shaders/vs.glsl"; 20 | import { Shader } from "@luma.gl/core"; 21 | export { vs, Shader };` 22 | }, 23 | { 24 | title: 'add default extension to d.ts imports', 25 | config: {afterDeclarations: true}, 26 | output: `\ 27 | export type { TypedArray } from "./types.js"; 28 | export { add } from "./math/add.js"; 29 | import vs from "../shaders/vs.glsl"; 30 | import { Shader } from "@luma.gl/core"; 31 | export { vs, Shader };` 32 | }, 33 | { 34 | title: 'add custom extension to js imports', 35 | config: {after: true, extensions: ['.mjs', '.glsl.mjs']}, 36 | output: `\ 37 | export { add } from "./math/add.mjs"; 38 | import vs from "../shaders/vs.glsl.mjs"; 39 | import { Shader } from "@luma.gl/core"; 40 | export { vs, Shader };` 41 | } 42 | ]; 43 | 44 | test('ts-transform-append-extension', (t) => { 45 | for (const testCase of testCases) { 46 | const result = transpile({ 47 | source: input, 48 | transformer: appendExtension, 49 | config: testCase.config, 50 | outputType: testCase.config.afterDeclarations ? 'd.ts' : 'js' 51 | }); 52 | 53 | t.is(assertSourceEqual(result, testCase.output), true, testCase.title); 54 | } 55 | 56 | t.end(); 57 | }); 58 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/index.spec.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import {fileURLToPath} from 'node:url'; 4 | 5 | import test from 'tape-promise/tape'; 6 | import {transpile, assertSourceEqual} from '../test-transformer.js'; 7 | // @ts-expect-error Aliased import, remapped to valid path in esm-loader 8 | import removeGLSLComments from 'ocular-dev-tools/ts-plugins/ts-transform-remove-glsl-comments'; 9 | 10 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); 11 | 12 | function loadSourceFromFile(fileName: string): string { 13 | return fs.readFileSync(path.join(__dirname, fileName), 'utf8'); 14 | } 15 | 16 | const testCases = [ 17 | { 18 | title: 'no comments', 19 | fileName: 'test.glsl.ts', 20 | config: {pattern: ['**/*.glsl.ts']}, 21 | input: 'test-case-0.ts', 22 | output: 'test-case-0-expected.ts' 23 | }, 24 | { 25 | title: 'remove comments from template literal', 26 | fileName: 'test.glsl.ts', 27 | config: {pattern: ['**/*.glsl.ts']}, 28 | input: 'test-case-1.ts', 29 | output: 'test-case-1-expected.ts' 30 | }, 31 | { 32 | title: 'excluded by file name', 33 | fileName: 'test.ts', 34 | config: {}, 35 | input: 'test-case-1.ts', 36 | output: 'test-case-1.ts' 37 | }, 38 | { 39 | title: 'included by template tag', 40 | fileName: 'test.ts', 41 | config: {}, 42 | input: 'test-case-2.ts', 43 | output: 'test-case-2-expected.ts' 44 | } 45 | ]; 46 | 47 | test('ts-transform-remove-glsl-comments', (t) => { 48 | for (const testCase of testCases) { 49 | const result = transpile({ 50 | sourceFileName: testCase.fileName, 51 | source: loadSourceFromFile(testCase.input), 52 | transformer: removeGLSLComments, 53 | config: testCase.config 54 | }); 55 | const expected = loadSourceFromFile(testCase.output); 56 | 57 | t.is(assertSourceEqual(result, expected, {ignoreEmptyLines: false}), true, testCase.title); 58 | } 59 | 60 | t.end(); 61 | }); 62 | -------------------------------------------------------------------------------- /website/gatsby-config.js: -------------------------------------------------------------------------------- 1 | const {resolve} = require('path'); 2 | 3 | // default location for table of contents 4 | const DOCS = require('../docs/table-of-contents.json'); 5 | 6 | module.exports = { 7 | plugins: [{ 8 | resolve: 'gatsby-theme-ocular', 9 | options: { 10 | // Adjusts amount of debug information from gatsby-theme-ocular 11 | logLevel: 1, 12 | 13 | DOC_FOLDERS: [ 14 | `${__dirname}/../docs/`, 15 | `${__dirname}/../modules/` 16 | ], 17 | ROOT_FOLDER: `${__dirname}/../`, 18 | SOURCE: [ 19 | `${__dirname}/static`, 20 | `${__dirname}/src` 21 | ], 22 | 23 | PROJECT_TYPE: 'github', 24 | PROJECT_NAME: 'Ocular', 25 | PROJECT_ORG: 'uber-web', 26 | PROJECT_ORG_LOGO: 'images/uber-logo.png', 27 | PROJECT_URL: 'https://github.com/uber-web/ocular', 28 | PROJECT_DESC: 'Uber\'s open source documentation system', 29 | PATH_PREFIX: '', 30 | 31 | LINK_TO_GET_STARTED: '/docs', 32 | PAGES: [ 33 | { 34 | path: '/', 35 | content: resolve('./src/home.md') 36 | }, 37 | { 38 | path: '/about', 39 | content: resolve('./src/about.md') 40 | } 41 | ], 42 | 43 | // your table of contents goes here 44 | DOCS, 45 | 46 | EXAMPLES: [ 47 | // { 48 | // title: 'Minimal Example', 49 | // path: 'examples/minimal', 50 | // image: 'images/hero.jpg', 51 | // componentUrl: resolve(__dirname, '../examples/minimal/app.js') 52 | // } 53 | ], 54 | 55 | // THEME_OVERRIDES: require('./src/theme.json'), 56 | 57 | PROJECTS: [ 58 | {name: 'deck.gl', url: 'https://deck.gl'}, 59 | {name: 'luma.gl', url: 'https://luma.gl'}, 60 | {name: 'loaders.gl', url: 'https://loaders.gl'} 61 | ], 62 | ADDITIONAL_LINKS: [ 63 | {name: 'About', href: '/about'} 64 | ], 65 | 66 | GA_TRACKING_ID: 'dummy_tracking_id', 67 | 68 | // For showing star counts and contributors. 69 | // Should be like btoa('YourUsername:YourKey') and should be readonly. 70 | GITHUB_KEY: null 71 | } 72 | }] 73 | }; 74 | -------------------------------------------------------------------------------- /website/static/images/icon-target.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | high-precision 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/dev-tools/dist/esm/app.js: -------------------------------------------------------------------------------- 1 | import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck"; 2 | import _createClass from "@babel/runtime/helpers/esm/createClass"; 3 | import _inherits from "@babel/runtime/helpers/esm/inherits"; 4 | import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn"; 5 | import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf"; 6 | 7 | function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } 8 | 9 | function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } 10 | 11 | import React, { PureComponent } from 'react'; 12 | import { render } from 'react-dom'; 13 | 14 | var App = function (_PureComponent) { 15 | _inherits(App, _PureComponent); 16 | 17 | var _super = _createSuper(App); 18 | 19 | function App(props) { 20 | var _this; 21 | 22 | _classCallCheck(this, App); 23 | 24 | _this = _super.call(this, props); 25 | _this.state = {}; 26 | return _this; 27 | } 28 | 29 | _createClass(App, [{ 30 | key: "render", 31 | value: function render() { 32 | return React.createElement("div", { 33 | style: { 34 | color: 'red' 35 | } 36 | }, React.createElement("p", null, "This is a minimal React example"), React.createElement("p", null, "Line..."), React.createElement("p", null, "Line..."), React.createElement("p", null, "Line..."), React.createElement("p", null, "Line...")); 37 | } 38 | }]); 39 | 40 | return App; 41 | }(PureComponent); 42 | 43 | export { App as default }; 44 | export function renderToDOM(container) { 45 | render(React.createElement(App, null), container); 46 | } 47 | //# sourceMappingURL=app.js.map -------------------------------------------------------------------------------- /modules/dev-tools/scripts/metrics.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script to collect build size information 3 | 4 | # set -ex 5 | 6 | export PATH=$PATH:node_modules/.bin 7 | 8 | DEV_TOOLS_DIR=$(dirname $0)/.. 9 | WORKING_DIR=`pwd` 10 | TMP_DIR=$WORKING_DIR/tmp 11 | 12 | # Get size metric entry point 13 | ENTRY_POINTS=`node $DEV_TOOLS_DIR/dist/helpers/get-config.js ".entry.size"` 14 | IFS=',' 15 | read -a ENTRY_POINTS_ARR <<< "$ENTRY_POINTS" 16 | IFS=' ' 17 | 18 | # Get name from package.json 19 | module=`node -e "console.log(require('./package.json').name)"` 20 | # Get version 21 | if [ -d "modules" ]; then 22 | # Use lerna version if monorepo 23 | packageInfo=./lerna.json 24 | else 25 | # Use package.json version if monorepo 26 | packageInfo=./package.json 27 | fi 28 | # Get version from packag.json and remove quotes 29 | version=`node -e "console.log(require('${packageInfo}').version)"` 30 | 31 | # Helper functions 32 | 33 | print_size_header() { 34 | echo -e "\033[1m| Version | Dist | Bundle Size | Compressed | Imports |\033[0m" 35 | echo "| --- | --- | --- | --- | --- |" 36 | } 37 | 38 | print_size() { 39 | DIST=$1 40 | cd $TMP_DIR 41 | 42 | for f in *; do ( 43 | # Size it 44 | size=$(wc -c $f | awk '{ print int($1 / 1024) "KB (" $1 ")" }') 45 | # Zip it 46 | gzip -9f $f 47 | # Size it again 48 | zipsize=$(wc -c $f.gz | awk '{ print int($1 / 1024) "KB (" $1 ")" }') # Size it 49 | # Remove our copy 50 | rm $f.gz 51 | # Print version, size, compressed size with markdown 52 | 53 | echo "| $version | $DIST | $size KB | $zipsize KB | $f " 54 | ); done 55 | 56 | cd $WORKING_DIR 57 | } 58 | 59 | build_bundle() { 60 | if [ "$2" == es5 ]; then 61 | DIST="main,module" 62 | else 63 | DIST="module,browser,main" 64 | fi 65 | (npx esbuild $1 --outdir="$TMP_DIR" --bundle --minify --main-fields=$DIST --log-level=error) 66 | } 67 | 68 | # Main Script 69 | 70 | echo 71 | echo -e "\033[93mAutomatically collecting metrics for $module\033[0m" 72 | echo 73 | 74 | rm -rf $TMP_DIR 75 | mkdir $TMP_DIR 76 | 77 | print_size_header 78 | 79 | for f in "${ENTRY_POINTS_ARR[@]}"; do 80 | build_bundle $f es5 81 | done 82 | print_size es5 83 | 84 | for f in "${ENTRY_POINTS_ARR[@]}"; do 85 | build_bundle $f esm 86 | done 87 | print_size esm 88 | 89 | rm -rf $TMP_DIR 90 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script to publish modules 3 | 4 | set -e 5 | 6 | usage() { 7 | # TODO: Add more specific url 8 | open "https://uber-web.github.io/ocular/docs/dev-tools/cli/ocular-publish" 9 | } 10 | 11 | BASEDIR=$(dirname "$0") 12 | 13 | ocular-bootstrap 14 | ocular-test 15 | ocular-test dist 16 | 17 | # beta or prod 18 | MODE=$1 19 | # custom tag 20 | TAG=$2 21 | 22 | if [ -d "modules" ]; then 23 | case $MODE in 24 | "help") 25 | usage 26 | ;; 27 | 28 | "beta") 29 | # npm-tag argument: npm publish --tag 30 | # cd-version argument: increase version 31 | if [ -z "$TAG" ] 32 | then 33 | (set -x; lerna publish prerelease --force-publish --exact --dist-tag beta --no-commit-hooks) 34 | else 35 | (set -x; lerna publish prerelease --force-publish --exact --dist-tag $TAG --no-commit-hooks) 36 | fi 37 | ;; 38 | 39 | "prod") 40 | if [ -z "$TAG" ] 41 | then 42 | # latest 43 | (set -x; lerna publish patch --force-publish --exact --no-commit-hooks) 44 | else 45 | (set -x; lerna publish patch --force-publish --exact --dist-tag $TAG --no-commit-hooks) 46 | fi 47 | ;; 48 | 49 | *) 50 | echo -e "\033[91mUnknown publish mode. ocular-publish ['prod' | 'beta']\033[0m" 51 | exit 1;; 52 | esac 53 | else 54 | case $MODE in 55 | "help") 56 | usage 57 | ;; 58 | 59 | "beta") 60 | # -f includes any changes in the version commit 61 | (set -x; npm version prerelease --force) 62 | # push to branch 63 | (set -x; git push && git push --tags) 64 | if [ -z "$TAG" ] 65 | then 66 | (set -x; npm publish --tag beta) 67 | else 68 | (set -x; npm publish --tag $TAG) 69 | fi 70 | ;; 71 | 72 | "prod") 73 | # -f includes any changes in the version commit 74 | (set -x; npm version patch --force) 75 | # push to branch 76 | (set -x; git push && git push --tags) 77 | 78 | if [ -z "$TAG" ] 79 | then 80 | # latest 81 | (set -x; npm publish) 82 | else 83 | (set -x; npm publish --tag $TAG) 84 | fi 85 | ;; 86 | 87 | *) 88 | echo -e "\033[91mUnknown publish mode. ocular-publish ['prod' | 'beta']\033[0m" 89 | exit 1;; 90 | esac 91 | fi 92 | -------------------------------------------------------------------------------- /website/static/images/icon-custom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | wrench 4 | Based on font-awesome and made with vim by balthazar ;) 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /modules/dev-tools/src/ts-plugins/ts-transform-version-inline/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * TypeScript transform to inject the current version of the package as string. 3 | * Usage with ts-patch: 4 | { 5 | "plugins": [ 6 | { 7 | "transform": "ocular-dev-tools/ts-transform-version-inline", 8 | "identifier": "PACKAGE_VERSION" 9 | } 10 | ] 11 | } 12 | */ 13 | import * as fs from 'fs'; 14 | import * as path from 'path'; 15 | import type {Program, TransformationContext, SourceFile, Node} from 'typescript'; 16 | import type {TransformerExtras, PluginConfig} from 'ts-patch'; 17 | 18 | type VersionInlinePluginConfig = PluginConfig & { 19 | /** Identifier name to replace in code. 20 | * @default "__VERSION__" 21 | */ 22 | identifier?: string; 23 | }; 24 | 25 | export default function ( 26 | program: Program, 27 | pluginConfig: VersionInlinePluginConfig, 28 | {ts}: TransformerExtras 29 | ) { 30 | const {identifier = '__VERSION__'} = pluginConfig; 31 | 32 | return (ctx: TransformationContext) => { 33 | const {factory} = ctx; 34 | 35 | return (sourceFile: SourceFile) => { 36 | let packageVersion: string | null; 37 | 38 | function visit(node: Node): Node { 39 | if ( 40 | ts.isIdentifier(node) && 41 | !ts.isPropertyAccessExpression(node.parent) && 42 | node.getText() === identifier 43 | ) { 44 | if (packageVersion === undefined) { 45 | packageVersion = getPackageVersion(sourceFile.fileName); 46 | } 47 | if (packageVersion) { 48 | return factory.createStringLiteral(packageVersion); 49 | } 50 | } 51 | return ts.visitEachChild(node, visit, ctx); 52 | } 53 | return ts.visitNode(sourceFile, visit); 54 | }; 55 | }; 56 | } 57 | 58 | /** 59 | * Retrieve the version string from the closest package.json 60 | */ 61 | function getPackageVersion(fileName: string): string | null { 62 | let currentDir = fileName; 63 | while (currentDir !== '/') { 64 | try { 65 | currentDir = path.dirname(currentDir); 66 | const packageJson = path.join(currentDir, 'package.json'); 67 | const stat = fs.statSync(packageJson); 68 | if (stat.isFile()) { 69 | const content = fs.readFileSync(packageJson, 'utf8'); 70 | return JSON.parse(content).version as string; 71 | } 72 | } catch { 73 | // file does not exist, try going up 74 | } 75 | } 76 | return null; 77 | } 78 | -------------------------------------------------------------------------------- /modules/dev-tools/src/helpers/aliases.ts: -------------------------------------------------------------------------------- 1 | // Registers an alias for this module 2 | import {resolve} from 'path'; 3 | import fs from 'fs'; 4 | import {getValidPath} from '../utils/utils.js'; 5 | import type {PackageJson} from '../utils/types.js'; 6 | 7 | type ModuleInfo = { 8 | name: string; 9 | path: string; 10 | packageInfo: PackageJson; 11 | }; 12 | 13 | export function getModuleInfo(path: string): ModuleInfo | null { 14 | if (fs.lstatSync(path).isDirectory()) { 15 | try { 16 | const packageInfoText = fs.readFileSync(resolve(path, 'package.json'), 'utf-8'); 17 | const packageInfo = JSON.parse(packageInfoText) as PackageJson; 18 | return { 19 | name: packageInfo.name, 20 | path, 21 | packageInfo 22 | }; 23 | } catch (err) { 24 | // ignore if sub directory does not contain package.json 25 | } 26 | } 27 | return null; 28 | } 29 | 30 | // Get information of all submodules 31 | function getSubmodules(packageRoot: string): {[name: string]: ModuleInfo} { 32 | const submodules: Record = {}; 33 | const parentPath = resolve(packageRoot, './modules'); 34 | 35 | if (fs.existsSync(parentPath)) { 36 | // monorepo 37 | fs.readdirSync(parentPath).forEach((item) => { 38 | const itemPath = resolve(parentPath, item); 39 | const moduleInfo = getModuleInfo(itemPath); 40 | if (moduleInfo) { 41 | submodules[moduleInfo.name] = moduleInfo; 42 | } 43 | }); 44 | } else { 45 | const moduleInfo = getModuleInfo(packageRoot); 46 | if (moduleInfo) { 47 | submodules[moduleInfo.name] = moduleInfo; 48 | } 49 | } 50 | 51 | return submodules; 52 | } 53 | 54 | export default function getAliases( 55 | mode: string, 56 | packageRoot: string = process.env.PWD! 57 | ): Record { 58 | const aliases: Record = {}; 59 | const submodules = getSubmodules(packageRoot); 60 | 61 | for (const moduleName in submodules) { 62 | const {path} = submodules[moduleName]; 63 | 64 | const testPath = resolve(path, 'test'); 65 | if (fs.existsSync(testPath)) { 66 | aliases[`${moduleName}/test`] = testPath; 67 | } 68 | 69 | if (mode === 'dist') { 70 | aliases[moduleName] = getValidPath( 71 | resolve(path, 'dist/es5'), 72 | resolve(path, 'dist/esm'), 73 | resolve(path, 'dist') 74 | )!; 75 | } else { 76 | aliases[moduleName] = resolve(path, 'src'); 77 | } 78 | } 79 | 80 | return aliases; 81 | } 82 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/lint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script to check code styles 3 | 4 | set -e 5 | 6 | # Lint selected directories 7 | # lint.sh DIR1,DIR2 8 | MODE=$1 9 | 10 | DEV_TOOLS_DIR=$(dirname $0)/.. 11 | 12 | DIRECTORIES=`node $DEV_TOOLS_DIR/dist/helpers/get-config.js ".lint.paths"` 13 | if [[ $DIRECTORIES == *","* ]]; then 14 | DIRECTORIES={$DIRECTORIES} 15 | fi 16 | 17 | EXTENSIONS=`node $DEV_TOOLS_DIR/dist/helpers/get-config.js ".lint.extensions"` 18 | if [[ $EXTENSIONS == *","* ]]; then 19 | EXTENSIONS={$EXTENSIONS} 20 | fi 21 | 22 | DIR_PATTERN="$DIRECTORIES/**/*.$EXTENSIONS" 23 | ROOT_PATTERN="*.$EXTENSIONS" 24 | 25 | usage() { 26 | # TODO: Add more specific url 27 | open "https://uber-web.github.io/ocular/docs/dev-tools/cli/ocular-lint" 28 | } 29 | 30 | print_yellow() { 31 | echo -e "\033[93m${1}\033[0m" 32 | } 33 | 34 | case $MODE in 35 | "help") 36 | usage 37 | ;; 38 | 39 | "pre-commit") 40 | print_yellow "Running prettier & eslint on changed files..." 41 | 42 | NAME_PATTERN=`echo "^$DIRECTORIES/.*\.$EXTENSIONS$" | sed -e 's/,/|/g' | sed -e 's/{/(/g' | sed -e 's/}/)/g'` 43 | 44 | # only check changed files 45 | set +e 46 | FILES=`git diff HEAD --name-only | grep -E "${NAME_PATTERN}"` 47 | set -e 48 | 49 | FILES_LIST="" 50 | 51 | if [ ! -z "${FILES}" ]; then 52 | for f in $FILES 53 | do 54 | if [ -e "${f}" ]; then 55 | FILES_LIST+="${f} " 56 | fi 57 | done 58 | 59 | (set -x; npx prettier-check $FILES_LIST) 60 | (set -x; npx eslint $FILES_LIST) 61 | fi 62 | ;; 63 | 64 | "fix") 65 | print_yellow "Running eslint in $DIRECTORIES..." 66 | (set -x; npx eslint --fix "$DIRECTORIES/**/*.$EXTENSIONS") 67 | 68 | print_yellow "Running prettier in $DIRECTORIES..." 69 | (set -x; npx prettier --log-level warn --write "$DIR_PATTERN" "$ROOT_PATTERN") 70 | ;; 71 | 72 | *) 73 | print_yellow "Running eslint in $DIRECTORIES..." 74 | (set -x; npx eslint "$DIRECTORIES/**/*.$EXTENSIONS") 75 | 76 | print_yellow "Checking prettier code style in $DIRECTORIES..." 77 | (set -x; npx prettier-check "$DIR_PATTERN" "$ROOT_PATTERN" || 78 | (echo -e "\033[91mNot all files using prettier code style. This may be fixed by running\033[0m \033[1mnpm run lint fix\033[0m" && 79 | exit 1)) 80 | 81 | ;; 82 | esac 83 | 84 | # check if yarn.lock contains private registry information 85 | !(grep -q unpm.u yarn.lock) && echo "Lockfile valid." || (echo -e "\033[91mPlease rebuild yarn file using public npmrc\033[0m" && false) 86 | -------------------------------------------------------------------------------- /modules/dev-tools/src/helpers/esm-loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Support module alias in ESM mode 3 | * tsconfig-paths does not work in ESM, see https://github.com/dividab/tsconfig-paths/issues/122 4 | * Adapted from https://github.com/TypeStrong/ts-node/discussions/1450 5 | */ 6 | import path from 'path'; 7 | import fs from 'fs'; 8 | import {pathToFileURL} from 'url'; 9 | import {resolve as resolveTs, getFormat, transformSource, load} from 'ts-node/esm'; 10 | import {getValidPath, ocularRoot} from '../utils/utils.js'; 11 | export {getFormat, transformSource, load}; 12 | 13 | // Load alias from file 14 | const pathJSON = fs.readFileSync(path.resolve(ocularRoot, '.alias.json'), 'utf-8'); 15 | const paths = JSON.parse(pathJSON); 16 | const matchPath = createMatchPath(paths); 17 | 18 | export function resolve(specifier, context, defaultResolver) { 19 | const mappedSpecifier = matchPath(specifier); 20 | if (mappedSpecifier) { 21 | if (mappedSpecifier.match(/(\/\*|\.jsx?|\.tsx?|\.cjs|\.json)$/)) { 22 | specifier = pathToFileURL(mappedSpecifier).pathname; 23 | } else if (mappedSpecifier.includes('/dist/')) { 24 | specifier = `${pathToFileURL(mappedSpecifier)}.js`; 25 | } else { 26 | specifier = `${pathToFileURL(mappedSpecifier)}`; 27 | } 28 | } 29 | const result = resolveTs(specifier, context, defaultResolver); 30 | return result; 31 | } 32 | 33 | /** Convert ocular alias object to TS config paths object */ 34 | function createMatchPath(aliases) { 35 | const tests = []; 36 | 37 | for (const key in aliases) { 38 | const alias = aliases[key]; 39 | let testFunc; 40 | if (key.includes('*')) { 41 | const regex = new RegExp(`^${key.replace('*', '(.+)')}`); 42 | testFunc = (specifier) => { 43 | const match = specifier.match(regex); 44 | if (match) { 45 | return specifier.replace(match[0], alias.replace('*', match[1])); 46 | } 47 | return null; 48 | }; 49 | } else { 50 | let defaultEntry = alias; 51 | 52 | if (!alias.match(/(\/\*|\.jsx?|\.tsx?|\.cjs)$/)) { 53 | defaultEntry = getValidPath(`${alias}/index.ts`, `${alias}/index.js`) || defaultEntry; 54 | } 55 | 56 | testFunc = (specifier) => { 57 | if (key === specifier) { 58 | return defaultEntry; 59 | } 60 | if (specifier.startsWith(`${key}/`)) { 61 | return `${alias}${specifier.slice(key.length)}`; 62 | } 63 | return null; 64 | }; 65 | } 66 | tests.push(testFunc); 67 | } 68 | 69 | return (specifier) => { 70 | for (const test of tests) { 71 | const result = test(specifier); 72 | if (result) { 73 | return result; 74 | } 75 | } 76 | return null; 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /docs/wip/gatsby-theme-ocular/get-started.md: -------------------------------------------------------------------------------- 1 | # Quick start 2 | 3 | ## Installing Ocular 4 | 5 | From the project you want to create a website for, create a new folder: 6 | 7 | ``` 8 | mkdir website 9 | ``` 10 | 11 | Initialize that folder as a new project with its own package.json. 12 | 13 | From now on, we'll call that folder you've just created the Ocular folder. 14 | 15 | ``` 16 | npm init -y 17 | ``` 18 | 19 | then install Ocular as a devDependency. 20 | 21 | ``` 22 | yarn add -D gatsby-theme-ocular 23 | ``` 24 | or 25 | ``` 26 | npm install gatsby-theme-ocular --save-dev 27 | ``` 28 | 29 | ## Creating and running your Ocular website 30 | 31 | Now, start the Ocular project: 32 | 33 | ``` 34 | ocular init 35 | ``` 36 | 37 | This will prompt you with a few questions, and create a number of files and folders in the Ocular folder. 38 | The most important of these file is `gatsby-config.js` in the Ocular folder, which contains all the settings for your website. You can edit it later. 39 | 40 | Now install any remaining packages: 41 | ``` 42 | yarn 43 | ``` 44 | or 45 | ``` 46 | npm install 47 | ``` 48 | 49 | Your project will need a `table-of-contents.json` file in the same location you have your documentation files. You can create one manually but Ocular can also create one for you by typing: 50 | ``` 51 | yarn build-toc 52 | ``` 53 | or 54 | ``` 55 | npm run build-toc 56 | ``` 57 | 58 | At this stage, you can see your website by typing: 59 | 60 | ``` 61 | yarn start 62 | ``` 63 | or 64 | ``` 65 | npm run start 66 | ``` 67 | 68 | ## Writing content 69 | 70 | You're going to need documentation files for your documentation website. 71 | Your `gatsby-config.js` file will contain the location of these files. Read [Writing documentation](./creating-content/writing-documentation) to know all about that part. 72 | And your documentation files will be available on your website! 73 | 74 | ## Publishing your website 75 | 76 | That's all you need if you just want to have your website running on your machine. But if you want to have your site running somewhere else, such as GitHub, that's not enough. 77 | 78 | From the ocular folder, type 79 | 80 | ``` 81 | yarn build 82 | ``` 83 | or 84 | ``` 85 | npm run build 86 | ``` 87 | And this will generate a static website in the folder `public` (a sub-folder of your Ocular folder) 88 | You can go to that folder and test your built website by typing 89 | ``` 90 | yarn serve 91 | ``` 92 | or 93 | ``` 94 | npm run serve 95 | ``` 96 | 97 | You can now safely upload the contents of this folder on a web server. If you want to deploy this website to GitHub Pages, and your project is already hosted on github, you can instead type: 98 | 99 | ``` 100 | yarn deploy 101 | ``` 102 | or 103 | ``` 104 | npm run deploy 105 | ``` 106 | -------------------------------------------------------------------------------- /modules/dev-tools/test/ts-plugins/test-transformer.ts: -------------------------------------------------------------------------------- 1 | import {Project, ts} from 'ts-morph'; 2 | import type {PluginConfig} from 'ts-patch'; 3 | 4 | /** 5 | * Transpile ts code with TypeScript compiler API 6 | */ 7 | export function transpile({ 8 | sourceFileName = 'test.ts', 9 | source, 10 | transformer, 11 | config = {}, 12 | outputType = 'js' 13 | }: { 14 | sourceFileName?: string; 15 | source: string; 16 | transformer: Function; 17 | config?: PluginConfig; 18 | outputType?: 'js' | 'd.ts'; 19 | }): string { 20 | const dts = outputType === 'd.ts'; 21 | 22 | const project = new Project({ 23 | compilerOptions: { 24 | target: ts.ScriptTarget.ESNext, 25 | module: ts.ModuleKind.ESNext, 26 | declaration: dts 27 | } 28 | }); 29 | 30 | project.createSourceFile(sourceFileName, source); 31 | 32 | const customTransformers: ts.CustomTransformers = {}; 33 | const transform: ts.TransformerFactory = transformer( 34 | project.getProgram(), 35 | config, 36 | {ts} 37 | ); 38 | if (config.after) { 39 | customTransformers.after = [transform]; 40 | } else if (config.afterDeclarations) { 41 | // @ts-ignore 42 | customTransformers.afterDeclarations = [transform]; 43 | } else { 44 | customTransformers.before = [transform]; 45 | } 46 | 47 | const result = project.emitToMemory({ 48 | customTransformers, 49 | emitOnlyDtsFiles: dts 50 | }); 51 | 52 | return result.getFiles()[0].text; 53 | } 54 | 55 | /** 56 | * Compare two pieces of source code. Returns a description of the difference, or null if identical. 57 | */ 58 | export function assertSourceEqual( 59 | actual: string, 60 | expected: string, 61 | options: { 62 | /** If true, ignore difference in indent 63 | * @default true 64 | */ 65 | ignoreIndent?: boolean; 66 | /** If true, ignore empty lines 67 | * @default true 68 | */ 69 | ignoreEmptyLines?: boolean; 70 | } = {} 71 | ): true | Error { 72 | const {ignoreIndent = true, ignoreEmptyLines = true} = options; 73 | const actualLines = actual.split('\n'); 74 | const expectedLines = expected.split('\n'); 75 | let i1 = 0; 76 | let i2 = 0; 77 | 78 | while (i1 < actualLines.length || i2 < expectedLines.length) { 79 | let t1 = actualLines[i1] ?? ''; 80 | let t2 = expectedLines[i2] ?? ''; 81 | if (ignoreIndent) { 82 | t1 = t1.trimStart(); 83 | t2 = t2.trimStart(); 84 | } 85 | if (t1 === t2) { 86 | i1++; 87 | i2++; 88 | } else if (ignoreEmptyLines && !t1) { 89 | i1++; 90 | } else if (ignoreEmptyLines && !t2) { 91 | i2++; 92 | } else { 93 | return new Error(`Mismatch at line ${i1} 94 | Actual: ${t1} 95 | Expected: ${t2} 96 | `); 97 | } 98 | } 99 | return true; 100 | } 101 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/cli/ocular-tsify.md: -------------------------------------------------------------------------------- 1 | # ocular-tsify 2 | 3 | Combine type declarations with related source files. 4 | 5 | ## Use 6 | 7 | Given a JavaScript file (or list of files) like so: 8 | 9 | ```bash 10 | npx ocular-tsify ./src/some-file.js 11 | ``` 12 | 13 | Will produce `.ts` files using nearby `.d.ts` files. 14 | 15 | ## Supported syntax 16 | The script parses `.d.ts` file, collects type declarations and runs typescript parser on `.js` file, injects types wherever a `JSDoc` type declaration is available. It supports most of the common `JSDoc` type declarations. 17 | 18 | ### 1. Type imports 19 | 20 | If importing from matching `.d.ts`, it will inline type declaration: 21 | 22 | from 23 | 24 | ```js 25 | /** @typedef {import('./geo-utils').GeoKey} GeoKey */ 26 | ``` 27 | 28 | to 29 | 30 | ```js 31 | export type GeoKey = { 32 | id: string, 33 | label: string, 34 | dataId: string 35 | }; 36 | ``` 37 | 38 | If importing from files other than matching `.d.ts`, will convert to type import. 39 | 40 | from 41 | 42 | ```js 43 | /** @typedef {import('./external-types').GeoState} GeoState */ 44 | ``` 45 | 46 | to 47 | 48 | ```js 49 | import type {GeoState} from './external-types'; 50 | ``` 51 | 52 | ### 2. Functions 53 | 54 | Functions with `JSDoc` type declaration using the `@type {typeof import('./').updater}` will be converted 55 | 56 | From 57 | 58 | ```js 59 | // js 60 | /** @type {typeof import('./reducers').createMapUpdater} */ 61 | const createMapUpdater = (state, action) => state 62 | 63 | // d.ts 64 | export declare function createMapUpdater(state: State, action: Action): State; 65 | ``` 66 | 67 | To 68 | 69 | ```js 70 | export function createMapUpdater(state: State, action: Action): State { 71 | ... 72 | } 73 | ``` 74 | 75 | # Known issues 76 | 77 | Here are some limitations and drawbacks of the scripts 78 | 79 | #### 1. Missing empty line inside functions 80 | Typescript compiler [doesn't preserve empty lines](https://github.com/microsoft/TypeScript/issues/843). When ocular-tsify injects types into functions, it will replace the existing JSDoc comment with an empty line, but empty lines inside the functions will be missing. So are empty lines between variable declarations that does not have JSDoc types. More improvements can be made such as insert empty before return statements. 81 | 82 | #### 2. Mixed import and export statement 83 | 84 | When type declarations are injected, they might come between import statements. Some manual cleanup is required. 85 | 86 | #### 3. Unsupported JSDoc `@returns` `@params` tags 87 | Only type declarations with the `@type` tag are supported. Some functions use separate tags such as below, future work can be done to support it. 88 | ```js 89 | /** 90 | * Currently not supported 91 | * @param {Dataset} dataset 92 | * @param {GeoKey} geoKey 93 | * @returns {Array} layers 94 | */ 95 | function defaultLayersForGeoKey(dataset, geoKey) {...} 96 | ``` 97 | -------------------------------------------------------------------------------- /examples/dev-tools/dist/es5/app.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); 4 | 5 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); 6 | 7 | Object.defineProperty(exports, "__esModule", { 8 | value: true 9 | }); 10 | exports.renderToDOM = renderToDOM; 11 | exports.default = void 0; 12 | 13 | var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); 14 | 15 | var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); 16 | 17 | var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); 18 | 19 | var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); 20 | 21 | var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); 22 | 23 | var _react = _interopRequireWildcard(require("react")); 24 | 25 | var _reactDom = require("react-dom"); 26 | 27 | function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; } 28 | 29 | function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } 30 | 31 | var App = function (_PureComponent) { 32 | (0, _inherits2.default)(App, _PureComponent); 33 | 34 | var _super = _createSuper(App); 35 | 36 | function App(props) { 37 | var _this; 38 | 39 | (0, _classCallCheck2.default)(this, App); 40 | _this = _super.call(this, props); 41 | _this.state = {}; 42 | return _this; 43 | } 44 | 45 | (0, _createClass2.default)(App, [{ 46 | key: "render", 47 | value: function render() { 48 | return _react.default.createElement("div", { 49 | style: { 50 | color: 'red' 51 | } 52 | }, _react.default.createElement("p", null, "This is a minimal React example"), _react.default.createElement("p", null, "Line..."), _react.default.createElement("p", null, "Line..."), _react.default.createElement("p", null, "Line..."), _react.default.createElement("p", null, "Line...")); 53 | } 54 | }]); 55 | return App; 56 | }(_react.PureComponent); 57 | 58 | exports.default = App; 59 | 60 | function renderToDOM(container) { 61 | (0, _reactDom.render)(_react.default.createElement(App, null), container); 62 | } 63 | //# sourceMappingURL=app.js.map -------------------------------------------------------------------------------- /dev-docs/RFCs/v1.0/gatsby-rfc.md: -------------------------------------------------------------------------------- 1 | # RCF: Rebuild ocular on top of gatsby 2 | 3 | Author: @jckr / @ibgreen 4 | Date: Jan 2019 5 | Status: Draft 6 | 7 | 8 | ## Requirements: 9 | 10 | * Treat documentation as code 11 | * Build from checked-in markdown 12 | * Handle examples 13 | * Build pages for examples (React and pure-js) 14 | * Inject examples from checked-in code. 15 | 16 | 17 | ## Static Website Generators 18 | 19 | Gatsby - Written in React (Note: not a documentation generator for React) - A downside is extensive use of complicated JS ecosystem. Requires a high bar to learn, but overlaps with the front-end skills used by React developers. 20 | 21 | Some strong alternatives 22 | - Jekyll, written in Ruby. 23 | - Hugo, is written in Go and uses Go's template libraries. 24 | 25 | Some articles 26 | - [Quick Thoughts on Gatsby JS vs. Jekyll](https://medium.com/@ajkueterman/quick-thoughts-on-gatsby-js-vs-jekyll-c13c1337c24a) 27 | - [Gatsby vs Hugo article](https://medium.freecodecamp.org/gatsby-vs-hugo-a-detailed-comparison-e78d94f640fc) 28 | - [Gatsby vs Jekyll vs Hugo forum](https://www.reddit.com/r/FreeCodeCamp/comments/923js6/jekyll_vs_hugo_vs_gatsby/) 29 | 30 | 31 | ## Markdown Support 32 | 33 | Markdown support is very strong, handled through the remark based plugin which itself has an entire system of sub-plugins for code syntax formatting, image handling, etc. Also a number of styling sheets are available. 34 | 35 | The main effort is deciding how to load all the markdown into gatsby, how to query it from the resulting graphql tables, and then generating table of contents, and styling the markdown. 36 | 37 | 38 | ## Code Injection Support 39 | 40 | ### Use Cases 41 | 42 | * Examples need to be browsable from their own table of contents - Just publish examples as separate pages and use iframes? 43 | * We want to be able to inject a code sample on a page 44 | 45 | 46 | ###Alternatives 47 | 48 | #### repl (code sandbox) links 49 | 50 | The gasby remark plugin [gatsby-remark-code-repls](https://www.gatsbyjs.org/packages/gatsby-remark-code-repls/) is an interesting of option for "REPL-type environments" (like codepen). This can POST example code from the repo to the codepen using the "Codepen Prefill API". 51 | * See [React docs](https://reactjs.org/docs/rendering-elements.html) for example usage. 52 | 53 | * Currently examples are not inline, the plugin generates links that open the code in the repl sandbox 54 | 55 | COMMENT: Adding this feature is obviously extremely nice for any complete code snippets, but does not solve the example code injection problem as such 56 | 57 | 58 | #### [gatsby-remark-responsive-iframe](https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-remark-responsive-iframe) 59 | 60 | Another gatsby remark plugin, wraps iframes or objects (e.g. embedded YouTube videos) within markdown files in a responsive elastic container with a fixed aspect ratio. This ensures that the iframe or object will scale proportionally and to the full width of its container. 61 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/bump.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import fs from 'fs'; 4 | import {resolve} from 'path'; 5 | import glob from 'glob'; 6 | import {execSync} from 'child_process'; 7 | 8 | const packageJsonFiles = glob.sync(resolve('**/package.json'), {ignore: '**/node_modules/**'}); 9 | console.log(packageJsonFiles); 10 | 11 | function getVersions(packageName) { 12 | const versions = execSync(`npm v ${packageName} dist-tags --json`, {encoding: 'utf8'}); 13 | return versions ? JSON.parse(versions) : null; 14 | } 15 | 16 | function getTargetVersion(packageAndVersion, moduleName) { 17 | const [, targetVersion] = packageAndVersion; 18 | let version = targetVersion; 19 | if (targetVersion === 'beta' || targetVersion === 'latest') { 20 | const versions = getVersions(moduleName); 21 | version = versions && versions[targetVersion]; 22 | } 23 | return version; 24 | } 25 | 26 | function bumpPackages(packages) { 27 | for (const file of packageJsonFiles) { 28 | let changed = false; 29 | let content = JSON.parse(fs.readFileSync(file, 'utf8')); 30 | const dependencies = content.dependencies || {}; 31 | const devDependencies = content.devDependencies || {}; 32 | const peerDependencies = content.peerDependencies || {}; 33 | 34 | for (const package_ of packages) { 35 | if (dependencies[package_.name]) { 36 | dependencies[package_.name] = `^${package_.version}`; 37 | changed = true; 38 | } 39 | if (devDependencies[package_.name]) { 40 | devDependencies[package_.name] = `^${package_.version}`; 41 | changed = true; 42 | } 43 | if (peerDependencies[package_.name]) { 44 | peerDependencies[package_.name] = `^${package_.version}`; 45 | changed = true; 46 | } 47 | } 48 | 49 | if (changed) { 50 | content = JSON.stringify(content, null, 2); 51 | fs.writeFileSync(file, `${content}\n`); 52 | } 53 | } 54 | } 55 | 56 | function main() { 57 | let packages = []; 58 | const args = process.argv; 59 | if (!args || args.length < 3) { 60 | console.error('Should provide at lease one package.'); 61 | return; 62 | } 63 | 64 | const argLen = args.length; 65 | for (let i = 2; i < argLen; i++) { 66 | const packageAndVersion = args[i].split('='); 67 | if (!packageAndVersion) { 68 | console.error('Should use format "yarn bump package" or "yarn bump package=target_version".'); 69 | return; 70 | } 71 | 72 | // default to latest version 73 | if (packageAndVersion.length === 1) { 74 | packageAndVersion.push('latest'); 75 | } 76 | 77 | const [packageName] = packageAndVersion; 78 | const modules = JSON.parse(execSync(`npm search ${packageName} --json`, {encoding: 'utf8'})); 79 | 80 | if (modules) { 81 | packages = packages.concat( 82 | modules.map(function (module) { 83 | const version = getTargetVersion(packageAndVersion, module.name); 84 | return { 85 | name: module.name, 86 | version 87 | }; 88 | }) 89 | ); 90 | } 91 | } 92 | 93 | if (packages.length) { 94 | bumpPackages(packages); 95 | } 96 | } 97 | 98 | main(); 99 | -------------------------------------------------------------------------------- /modules/dev-tools/scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | DEV_TOOLS_DIR=$(dirname $0)/.. 6 | CONFIG=`node $DEV_TOOLS_DIR/dist/helpers/get-config.js ".babel.configPath"` 7 | MODULES=`node $DEV_TOOLS_DIR/dist/helpers/get-config.js ".modules" | sed -E "s/,/ /g"` 8 | EXTENSIONS=`node $DEV_TOOLS_DIR/dist/helpers/get-config.js ".babel.extensions"` 9 | TS_PROJECT=`node $DEV_TOOLS_DIR/dist/helpers/get-config.js ".typescript.project"` 10 | IS_ESM=`node $DEV_TOOLS_DIR/dist/helpers/get-config.js ".esm"` 11 | 12 | check_target() { 13 | if [[ ! "$1" =~ ^es5|esm ]]; then 14 | echo -e "\033[91mUnknown build target $1. ocular-build [--dist es5|esm,...] [module1,...]\033[0m" 15 | exit 1 16 | fi 17 | } 18 | 19 | build_src() { 20 | OUT_DIR=$1 21 | TARGET=$2 22 | check_target $TARGET 23 | 24 | if [ ! -z "$CONFIG" ]; then 25 | (set -x; BABEL_ENV=$TARGET npx babel src --config-file $CONFIG --out-dir $OUT_DIR --copy-files --source-maps --extensions $EXTENSIONS) 26 | fi 27 | } 28 | 29 | build_module_esm() { 30 | build_src dist esm-strict 31 | node $DEV_TOOLS_DIR/dist/build-cjs.js 32 | } 33 | 34 | build_module() { 35 | if [ -z "$1" ]; then 36 | TARGETS="esm es5" 37 | else 38 | TARGETS=$* 39 | fi 40 | N=`echo "$TARGETS" | wc -w` 41 | if [ $N -eq 1 ]; then 42 | build_src dist $TARGETS 43 | else 44 | for T in ${TARGETS}; do( 45 | build_src dist/$T $T 46 | ); done 47 | fi 48 | } 49 | 50 | build_unirepo() { 51 | if [ "$IS_ESM" = "true" ]; then 52 | build_module_esm 53 | else 54 | build_module 55 | fi 56 | } 57 | 58 | build_monorepo() { 59 | while [ -n "$1" ]; do 60 | if [[ "$1" =~ ^\-\-[A-Za-z]+ ]]; then 61 | case "$1" in 62 | --dist) 63 | TARGET=$2 64 | shift ;; 65 | *) 66 | echo -e "\033[91mUnknown option $1. ocular-build [--dist es5|esm,...] [module1,...]\033[0m" 67 | exit 1 ;; 68 | esac 69 | else 70 | # Build selected modules 71 | # build.sh MODULE1,MODULE2 72 | MODULES=`echo $1 | sed -e 's/,/ modules\//g' | sed -e 's/^/modules\//g'` 73 | fi 74 | shift 75 | done 76 | 77 | if [ -z "$MODULES" ]; then 78 | # Build all modules 79 | MODULES=`find modules -mindepth 1 -maxdepth 1 -not \( -name ".*" \)` 80 | fi 81 | 82 | for D in ${MODULES}; do ( 83 | if [ -e "${D}/package.json" ]; then 84 | echo -e "\033[1mBuilding $D\033[0m" 85 | cd $D 86 | if [ "$IS_ESM" = "true" ]; then 87 | build_module_esm 88 | else 89 | build_module `echo $TARGET | sed -e 's/,/ /g'` 90 | fi 91 | echo "" 92 | elif [ ! -e "${D}" ]; then 93 | echo -e "\033[1mWarning: skipping $D because it doesn't match any file.\033[0m" 94 | echo -e "\033[1mHint: modules must be specified using full path relative to the project root.\033[0m" 95 | echo "" 96 | fi 97 | ); done 98 | } 99 | 100 | if [ ! -z "$TS_PROJECT" ]; then 101 | npx tspc -b $TS_PROJECT --verbose 102 | fi 103 | 104 | if [ -d "modules" ]; then 105 | build_monorepo $* 106 | else 107 | build_unirepo 108 | fi 109 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es5/stylistic-issues.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-array-constructor": 2, 4 | "no-bitwise": 0, 5 | "no-inline-comments": 2, 6 | "no-lonely-if": 2, 7 | "no-mixed-spaces-and-tabs": [ 8 | 2, 9 | false 10 | ], 11 | "linebreak-style": [ 12 | 2, 13 | "unix" 14 | ], 15 | "no-multiple-empty-lines": [ 16 | 2, 17 | { 18 | "max": 1 19 | } 20 | ], 21 | "no-nested-ternary": 0, 22 | "no-new-object": 2, 23 | "no-plusplus": 0, 24 | "no-ternary": 0, 25 | "no-trailing-spaces": 2, 26 | "no-underscore-dangle": 0, 27 | "no-unneeded-ternary": 2, 28 | "array-bracket-spacing": [ 29 | 2, 30 | "never" 31 | ], 32 | "block-spacing": [ 33 | 2, 34 | "always" 35 | ], 36 | "brace-style": [ 37 | 2, 38 | "1tbs" 39 | ], 40 | "camelcase": 2, 41 | "comma-dangle": [ 42 | 2, 43 | "never" 44 | ], 45 | "comma-spacing": [ 46 | 2, 47 | { 48 | "before": false, 49 | "after": true 50 | } 51 | ], 52 | "comma-style": [ 53 | 2, 54 | "last" 55 | ], 56 | "computed-property-spacing": [ 57 | 2, 58 | "never" 59 | ], 60 | "consistent-this": [ 61 | 2, 62 | "self" 63 | ], 64 | "eol-last": 2, 65 | "func-names": 2, 66 | "func-style": [ 67 | 0, 68 | "declaration" 69 | ], 70 | "id-length": 0, 71 | "id-match": 0, 72 | "indent": [ 73 | 2, 74 | 2 75 | ], 76 | "key-spacing": [ 77 | 2, 78 | { 79 | "beforeColon": false, 80 | "afterColon": true 81 | } 82 | ], 83 | "max-depth": [ 84 | 2, 85 | 3 86 | ], 87 | "max-len": [ 88 | 2, 89 | 100, 90 | 4 91 | ], 92 | "max-nested-callbacks": [ 93 | 2, 94 | 3 95 | ], 96 | "max-params": [ 97 | 2, 98 | 5 99 | ], 100 | "max-statements": [ 101 | 2, 102 | 25 103 | ], 104 | "new-cap": [ 105 | 2, 106 | { 107 | "newIsCap": true, 108 | "capIsNew": false 109 | } 110 | ], 111 | "new-parens": 2, 112 | "newline-after-var": 0, 113 | "object-curly-spacing": [ 114 | 2, 115 | "never" 116 | ], 117 | "one-var": [ 118 | 2, 119 | "never" 120 | ], 121 | "operator-assignment": [ 122 | 0, 123 | "always" 124 | ], 125 | "operator-linebreak": [ 126 | 2, 127 | "after" 128 | ], 129 | "padded-blocks": 0, 130 | "quotes": [ 131 | 2, 132 | "single" 133 | ], 134 | "semi": 2, 135 | "semi-spacing": [ 136 | 2, 137 | { 138 | "before": false, 139 | "after": true 140 | } 141 | ], 142 | "keyword-spacing": [ 143 | 2 144 | ], 145 | "space-before-blocks": [ 146 | 2, 147 | "always" 148 | ], 149 | "space-before-function-paren": [ 150 | 2, 151 | "never" 152 | ], 153 | "space-in-parens": [ 154 | 2, 155 | "never" 156 | ], 157 | "space-infix-ops": 2, 158 | "space-unary-ops": [ 159 | 2, 160 | { 161 | "words": true, 162 | "nonwords": false 163 | } 164 | ], 165 | "spaced-comment": [ 166 | 2, 167 | "always", 168 | { 169 | "exceptions": [ 170 | "-", 171 | "=", 172 | "+", 173 | "*" 174 | ] 175 | } 176 | ] 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /modules/dev-tools/src/ts-plugins/ts-transform-append-extension/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * TypeScript transform to append file extension to import statements in the compiled JS files 3 | * Usage with ts-patch: 4 | { 5 | "plugins": [ 6 | { 7 | "transform": "ocular-dev-tools/ts-transform-append-extension", 8 | "extensions": [".js"], 9 | "after": true 10 | } 11 | ] 12 | } 13 | * Adapted from https://github.com/murolem/ts-transformer-append-js-extension to support custom extensions 14 | */ 15 | import * as path from 'path'; 16 | import type {Program, TransformationContext, SourceFile, Node} from 'typescript'; 17 | import type {TransformerExtras, PluginConfig} from 'ts-patch'; 18 | 19 | type AppendExtensionPluginConfig = PluginConfig & { 20 | /** List of file extensions, for example: 21 | * '.js': applies to paths without an extension, e.g. `import {add} from './math'` => `import {add} from './math.js'` 22 | * '.lib.cjs': applies to paths ending with .lib, e.g. `import fft from './fft.lib` => `import fft from './fft.lib.cjs'` 23 | * @default [".js"] 24 | */ 25 | extensions?: string[]; 26 | }; 27 | 28 | export default function ( 29 | program: Program, 30 | pluginConfig: AppendExtensionPluginConfig, 31 | {ts}: TransformerExtras 32 | ) { 33 | // only append .js when module specifier has no extension or user-provided extensions 34 | const {extensions = ['.js']} = pluginConfig; 35 | const extMappings = new Map(); 36 | for (const ext of extensions) { 37 | const addition = path.extname(ext) || ext; 38 | const base = path.basename(ext, addition); 39 | extMappings.set(base, addition); 40 | } 41 | 42 | function shouldMutateModuleSpecifier(node: Node): string | false { 43 | if (!ts.isImportDeclaration(node) && !ts.isExportDeclaration(node)) return false; 44 | if (node.moduleSpecifier === undefined) return false; 45 | // only when module specifier is valid 46 | if (!ts.isStringLiteral(node.moduleSpecifier)) return false; 47 | // only when path is relative 48 | if (!node.moduleSpecifier.text.startsWith('./') && !node.moduleSpecifier.text.startsWith('../')) 49 | return false; 50 | // only when module specifier has accepted extension 51 | const ext = path.extname(node.moduleSpecifier.text); 52 | if (!extMappings.has(ext)) return false; 53 | return node.moduleSpecifier.text + extMappings.get(ext); 54 | } 55 | 56 | return (ctx: TransformationContext) => { 57 | const {factory} = ctx; 58 | 59 | return (sourceFile: SourceFile) => { 60 | function visit(node: Node): Node { 61 | const newImportSource = shouldMutateModuleSpecifier(node); 62 | if (newImportSource) { 63 | if (ts.isImportDeclaration(node)) { 64 | const newModuleSpecifier = factory.createStringLiteral(newImportSource); 65 | node = factory.updateImportDeclaration( 66 | node, 67 | node.modifiers, 68 | node.importClause, 69 | newModuleSpecifier, 70 | node.assertClause 71 | ); 72 | } else if (ts.isExportDeclaration(node)) { 73 | const newModuleSpecifier = factory.createStringLiteral(newImportSource); 74 | node = factory.updateExportDeclaration( 75 | node, 76 | node.modifiers, 77 | node.isTypeOnly, 78 | node.exportClause, 79 | newModuleSpecifier, 80 | node.assertClause 81 | ); 82 | } 83 | } 84 | 85 | return ts.visitEachChild(node, visit, ctx); 86 | } 87 | 88 | return ts.visitNode(sourceFile, visit); 89 | }; 90 | }; 91 | } 92 | -------------------------------------------------------------------------------- /docs/wip/gatsby-theme-ocular/README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | Ocular is a tool primarily designed for building documentation websites for github-based javascript frameworks, built using the gatsbyjs documentation generation system. 4 | 5 | Using ocular in your framework requires: 6 | * a directory with github markdown 7 | * examples... 8 | 9 | 10 | ## Quick Setup 11 | 12 | If you already have markdown documentation written for your framework, setting up an initial ocular based page is very quick: 13 | 14 | * Create a `website` folder in your framework repository's root folder. 15 | * Create a package.json and install `ocular` in the website folder. 16 | * Create the file `website/gatsby-config.js`, copied from ... 17 | * Create the file `website/gatsby-node.js`, copied from ... 18 | * Create the file `website/site-config.js`, copied from and modified to fit your site. 19 | * Create a `table-of-contents.json` at the root of your markdown documentation folder. 20 | 21 | 22 | ## Deep Configuration 23 | 24 | Since your website contains the gatsbyjs entry point files (`gatsby-config.js` and `gatsby-node.js`) it is possible to take full control and override selected parts of ocular's documenation generation system. 25 | 26 | The ocular package exports most internal components used by ocular so that you can reuse them in building customized functionality. 27 | 28 | 29 | ## Functions 30 | 31 | ### getGatsbyConfig(options : Object) : Object 32 | 33 | This function takes your site configuration object and builds a complete gatsby configuration object, and populates it with a number of preinstalled plugins. This object is intended to be passed to gatsby as the exported value from your `website/gatsby-config.js` file. 34 | 35 | `getGatsbyConfig` is intended to be called in your `website/gatsby-config.js` file as follows: 36 | 37 | ``` 38 | require('reify'); // Enables ES6 "import" in imported files 39 | 40 | const {setSiteConfig, getGatsbyConfig} = require('ocular'); 41 | 42 | const config = require('./ocular-config'); 43 | 44 | setSiteConfig(config); 45 | 46 | module.exports = getGatsbyConfig(config); 47 | ``` 48 | 49 | NOTE: You can forward the returned object directly to gatsby, or you can modify it first, e.g. to delete or add plugins before passing it on to gatsby. Consult [gatsby docs](https://www.gatsbyjs.org/) for more information on `gatsby-config.js` options. 50 | 51 | 52 | ### getGatsbyNodeCallbacks() : Object 53 | 54 | Forward these callbacks to gatsby in your `website/gatsby-node.js` file to set up default ocular configuration. 55 | 56 | ``` 57 | require('reify'); // Enables ES6 "import" in imported files 58 | const {getGatsbyNodeCallbacks} = require('ocular'); 59 | 60 | module.exports = getGatsbyNodeCallbacks(); 61 | ``` 62 | 63 | NOTE: It is possible to override the ocular-provided callbacks and thus take full control of any aspect of gatsby's document generation process. Consult [gatsby docs](https://www.gatsbyjs.org/) for more information on `gatsby-node.js` callbacks. 64 | 65 | ``` 66 | require('reify'); // Enables ES6 "import" in imported files 67 | const {getGatsbyNodeCallbacks} = require('ocular'); 68 | 69 | module.exports = getGatsbyNodeCallbacks(); 70 | module.exports.onCreateNode = ({ node, actions, getNode }) => { 71 | // Do other things 72 | ... 73 | /// Call ocular default handling (or not) 74 | getGatsbyNodeCallbacks.onCreateNode({ node, actions, getNode }); 75 | }; 76 | ``` 77 | 78 | 79 | ## Components 80 | 81 | ocular provides a number of common React components that can be used to create custom pages. 82 | 83 | 84 | ### Layouts 85 | 86 | Layout components are components that remain static between pages 87 | 88 | 89 | #### Header 90 | 91 | 92 | #### Footer 93 | 94 | 95 | #### Table of Contents 96 | 97 | 98 | ### Common Components 99 | 100 | 101 | #### SEO 102 | 103 | Search engine optimization helper 104 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/eslint-config-uber-es5/errors.json: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | // These rules relate to possible syntax or logic errors 22 | // Categorized as "errors" here: http://eslint.org/docs/rules/ 23 | { 24 | "rules": { 25 | /** 26 | * Possible Errors Section from http://eslint.org/docs/rules/: 27 | */ 28 | 29 | // http://eslint.org/docs/rules/no-cond-assign 30 | "no-cond-assign": 2, 31 | 32 | // http://eslint.org/docs/rules/no-constant-condition 33 | "no-constant-condition": 2, 34 | 35 | // http://eslint.org/docs/rules/no-console 36 | // highly agreed upon 37 | "no-console": 2, 38 | 39 | // http://eslint.org/docs/rules/no-control-regex 40 | "no-control-regex": 2, 41 | 42 | // http://eslint.org/docs/rules/no-debugger 43 | // highly agreed upon 44 | "no-debugger": 2, 45 | 46 | // http://eslint.org/docs/rules/no-dupe-args 47 | "no-dupe-args": 2, 48 | 49 | // http://eslint.org/docs/rules/no-dupe-keys 50 | "no-dupe-keys": 2, 51 | 52 | // http://eslint.org/docs/rules/no-duplicate-case 53 | "no-duplicate-case": 2, 54 | 55 | // http://eslint.org/docs/rules/no-empty-character-class 56 | "no-empty-character-class": 2, 57 | 58 | // http://eslint.org/docs/rules/no-empty 59 | // highly agreed upon 60 | "no-empty": 2, 61 | 62 | // http://eslint.org/docs/rules/no-ex-assign 63 | // abnormal behavior in ie 6-8 64 | "no-ex-assign": 2, 65 | 66 | // http://eslint.org/docs/rules/no-extra-boolean-cast 67 | // highly agreed upon 68 | "no-extra-boolean-cast": 2, 69 | 70 | // http://eslint.org/docs/rules/no-extra-parens 71 | "no-extra-parens": [2, "functions"], 72 | 73 | // http://eslint.org/docs/rules/no-extra-semi 74 | // highly agreed upon 75 | "no-extra-semi": 2, 76 | 77 | // http://eslint.org/docs/rules/no-func-assign 78 | "no-func-assign": 2, 79 | 80 | // http://eslint.org/docs/rules/no-inner-declarations 81 | "no-inner-declarations": [2, "functions"], 82 | 83 | "no-invalid-regexp": 2, 84 | 85 | "no-irregular-whitespace": 2, 86 | 87 | "no-obj-calls": 2, 88 | 89 | // http://eslint.org/docs/rules/no-prototype-builtins 90 | "no-prototype-builtins": 0, 91 | 92 | "no-regex-spaces": 2, 93 | 94 | "no-sparse-arrays": 2, 95 | 96 | // http://eslint.org/docs/rules/no-template-curly-in-string 97 | "no-template-curly-in-string": 2, 98 | 99 | "no-unexpected-multiline": 2, 100 | 101 | "no-unreachable": 2, 102 | 103 | // http://eslint.org/docs/rules/no-unsafe-finally 104 | "no-unsafe-finally": 2, 105 | 106 | // http://eslint.org/docs/rules/no-unsafe-negation 107 | "no-unsafe-negation": 2, 108 | 109 | "use-isnan": 2, 110 | 111 | "valid-jsdoc": 0, 112 | 113 | "valid-typeof": 2 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /modules/dev-tools/src/ts-plugins/ts-transform-remove-glsl-comments/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * TypeScript transform to remove comments and unnecessary white space from GLSL source. 3 | * A template string is considered GLSL source if: 4 | a) the file matches the pattern specified in the plugin config; or 5 | b) it is tagged as glsl`...` 6 | * Usage with ts-patch: 7 | { 8 | "plugins": [ 9 | { 10 | "transform": "ocular-dev-tools/ts-transform-remove-glsl-comments", 11 | "pattern": ["*.glsl.ts"] 12 | } 13 | ] 14 | } 15 | */ 16 | import * as path from 'path'; 17 | import type {Program, TransformationContext, SourceFile, Node} from 'typescript'; 18 | import type {TransformerExtras, PluginConfig} from 'ts-patch'; 19 | import minimatch from 'minimatch'; 20 | 21 | // inline comment is only safe to remove if it's followed by a return (i.e. end of comment) 22 | const INLINE_COMMENT_REGEX = /\s*\/\/.*[\n\r]/g; 23 | const BLOCK_COMMENT_REGEX = /\s*\/\*(\*(?!\/)|[^*])*\*\//g; 24 | const WHITESPACE_REGEX = /\s*[\n\r]\s*/gm; 25 | const DEFAULT_PATTERNS = []; 26 | 27 | type RemoveGLSLCommentsPluginConfig = PluginConfig & { 28 | /** Glob patterns of shader files to include. */ 29 | pattern?: string[]; 30 | }; 31 | 32 | export default function ( 33 | program: Program, 34 | pluginConfig: RemoveGLSLCommentsPluginConfig, 35 | {ts}: TransformerExtras 36 | ) { 37 | const {pattern = DEFAULT_PATTERNS} = pluginConfig; 38 | 39 | return (ctx: TransformationContext) => { 40 | const {factory} = ctx; 41 | 42 | return (sourceFile: SourceFile) => { 43 | const isShaderFile = matchFilePath(sourceFile.fileName, pattern); 44 | 45 | function replaceShaderString(node: Node): Node { 46 | if (ts.isNoSubstitutionTemplateLiteral(node)) { 47 | const text = node.rawText ?? ''; 48 | // Convert source text to string content 49 | const newText = filterShaderSource(text); 50 | if (newText === text) { 51 | return node; 52 | } 53 | return factory.createNoSubstitutionTemplateLiteral(newText, newText); 54 | } 55 | if (ts.isTemplateLiteralToken(node)) { 56 | const text = node.rawText ?? ''; 57 | const newText = filterShaderSource(text); 58 | if (newText === text) { 59 | return node; 60 | } 61 | if (ts.isTemplateHead(node)) { 62 | return factory.createTemplateHead(newText, newText); 63 | } 64 | if (ts.isTemplateMiddle(node)) { 65 | return factory.createTemplateMiddle(newText, newText); 66 | } 67 | if (ts.isTemplateTail(node)) { 68 | return factory.createTemplateTail(newText, newText); 69 | } 70 | return node; 71 | } 72 | return ts.visitEachChild(node, replaceShaderString, ctx); 73 | } 74 | 75 | function visit(node: Node): Node { 76 | if ( 77 | ts.isTaggedTemplateExpression(node) && 78 | // First child is the tag identifier 79 | node.getChildAt(0).getText() === 'glsl' 80 | ) { 81 | // Strip the template tag 82 | return replaceShaderString(node.getChildAt(1)); 83 | } 84 | if (isShaderFile && ts.isTemplateLiteral(node)) { 85 | return replaceShaderString(node); 86 | } 87 | return ts.visitEachChild(node, visit, ctx); 88 | } 89 | return ts.visitNode(sourceFile, visit); 90 | }; 91 | }; 92 | } 93 | 94 | function matchFilePath(filePath: string, includePatterns: string[]): boolean { 95 | const relPath = path.relative(process.env.PWD ?? '', filePath); 96 | for (const pattern of includePatterns) { 97 | if (minimatch(relPath, pattern)) { 98 | return true; 99 | } 100 | } 101 | return false; 102 | } 103 | 104 | function filterShaderSource(source: string): string { 105 | return source 106 | .replace(INLINE_COMMENT_REGEX, '\n') 107 | .replace(BLOCK_COMMENT_REGEX, '') 108 | .replace(WHITESPACE_REGEX, '\n'); 109 | } 110 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/get-babel-config.ts: -------------------------------------------------------------------------------- 1 | import deepMerge from 'deepmerge'; 2 | import {inspect} from 'util'; 3 | 4 | // The following targets are designed to support the most commonly used evergreen browsers. 5 | // As of Feb 2021 they all support async function, async iterator, and spread operator. 6 | const ES5_TARGETS = ['>0.2%', 'maintained node versions', 'not ie 11', 'not dead', 'not chrome 49']; 7 | const ESM_TARGETS = ['>0.2% and supports async-functions', 'maintained node versions', 'not dead']; 8 | // Reduce verbosity 9 | const ESM_PLUGIN_BLACKLIST = [ 10 | // Template literals are supported in all latest versions of environments 11 | '@babel/plugin-transform-template-literals' 12 | ]; 13 | 14 | const DEFAULT_CONFIG = { 15 | comments: false, 16 | // These settings reduce the verbosity of transpile outputs 17 | assumptions: { 18 | // When declaring classes, assume that methods don't shadow getters on the superclass and that the program doesn't depend on methods being non-enumerable. 19 | setClassMethods: true, 20 | // When using public class fields, assume that they don't shadow any getter in the current class, in its subclasses or in its superclass. 21 | setPublicClassFields: true 22 | } 23 | }; 24 | 25 | const COMMON_PRESETS = [ 26 | // Accepts typescript syntax 27 | // Note that this still has limits (requires typescript isolated modules) 28 | '@babel/preset-typescript' 29 | ]; 30 | 31 | const COMMON_PLUGINS = []; 32 | 33 | const ENV_CONFIG: any = { 34 | // fully transpiled build 35 | es5: { 36 | presets: [ 37 | ...COMMON_PRESETS, 38 | [ 39 | '@babel/env', 40 | { 41 | targets: ES5_TARGETS, 42 | modules: 'commonjs' 43 | } 44 | ] 45 | ], 46 | plugins: [...COMMON_PLUGINS, '@babel/transform-runtime'] 47 | }, 48 | // es module style build 49 | esm: { 50 | presets: [ 51 | ...COMMON_PRESETS, 52 | [ 53 | '@babel/env', 54 | { 55 | targets: ESM_TARGETS, 56 | exclude: ESM_PLUGIN_BLACKLIST, 57 | modules: false 58 | } 59 | ] 60 | ], 61 | plugins: [ 62 | ...COMMON_PLUGINS, 63 | // TODO - we likely do not need runtime transforms for the esm setting 64 | ['@babel/transform-runtime', {useESModules: true}] 65 | ] 66 | }, 67 | 68 | 'esm-strict': { 69 | presets: [ 70 | ...COMMON_PRESETS, 71 | [ 72 | '@babel/env', 73 | { 74 | targets: ESM_TARGETS, 75 | exclude: ESM_PLUGIN_BLACKLIST, 76 | modules: false 77 | } 78 | ] 79 | ], 80 | plugins: [ 81 | ...COMMON_PLUGINS, 82 | 'babel-plugin-add-import-extension', 83 | // TODO - we likely do not need runtime transforms for the esm setting 84 | ['@babel/transform-runtime', {useESModules: true}] 85 | ] 86 | }, 87 | 88 | bundle: { 89 | presets: [ 90 | ...COMMON_PRESETS, 91 | [ 92 | '@babel/env', 93 | { 94 | targets: ESM_TARGETS, 95 | modules: false 96 | } 97 | ] 98 | ] 99 | }, 100 | 101 | 'bundle-dev': { 102 | presets: [...COMMON_PRESETS] 103 | } 104 | }; 105 | 106 | // Ensure we have an entry for the default BABEL_ENV 107 | ENV_CONFIG.development = ENV_CONFIG.es5; 108 | 109 | export function getBabelConfig( 110 | options: { 111 | react?: boolean; 112 | overrides?: any; 113 | debug?: boolean; 114 | } = {} 115 | ) { 116 | return (api) => { 117 | if (api.cache) { 118 | api.cache.using(() => process.env.BABEL_ENV); 119 | } 120 | 121 | let config = { 122 | ...DEFAULT_CONFIG, 123 | ...ENV_CONFIG[api.env()] 124 | }; 125 | if (options.react) { 126 | config = deepMerge(config, { 127 | presets: ['@babel/preset-react'] 128 | }); 129 | } 130 | if (options.overrides) { 131 | config = deepMerge(config, options.overrides); 132 | } 133 | 134 | if (options.debug) { 135 | console.log(inspect(config, {colors: true, depth: null})); 136 | } 137 | 138 | return config; 139 | }; 140 | } 141 | -------------------------------------------------------------------------------- /modules/dev-tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ocular-dev-tools", 3 | "description": "Dev tools for our Javascript frameworks", 4 | "license": "MIT", 5 | "version": "2.0.0-alpha.29", 6 | "type": "module", 7 | "keywords": [ 8 | "javascript" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/uber-web/ocular/" 13 | }, 14 | "files": [ 15 | "src", 16 | "scripts", 17 | "templates", 18 | "dist", 19 | "CHANGELOG.md" 20 | ], 21 | "exports": { 22 | ".": { 23 | "types": "./dist/index.d.ts", 24 | "require": "./dist/index.cjs", 25 | "import": "./dist/index.js" 26 | }, 27 | "./configuration": { 28 | "types": "./dist/configuration/index.d.ts", 29 | "require": "./dist/configuration/index.cjs", 30 | "import": "./dist/configuration/index.js" 31 | }, 32 | "./ts-transform-version-inline": { 33 | "require": "./dist/ts-plugins/ts-transform-version-inline/index.cjs", 34 | "import": "./dist/ts-plugins/ts-transform-version-inline/index.js" 35 | }, 36 | "./ts-transform-append-extension": { 37 | "require": "./dist/ts-plugins/ts-transform-append-extension/index.cjs", 38 | "import": "./dist/ts-plugins/ts-transform-append-extension/index.js" 39 | }, 40 | "./ts-transform-remove-glsl-comments": { 41 | "require": "./dist/ts-plugins/ts-transform-remove-glsl-comments/index.cjs", 42 | "import": "./dist/ts-plugins/ts-transform-remove-glsl-comments/index.js" 43 | }, 44 | "./ts-transform-inline-webgl-constants": { 45 | "require": "./dist/ts-plugins/ts-transform-inline-webgl-constants/index.cjs", 46 | "import": "./dist/ts-plugins/ts-transform-inline-webgl-constants/index.js" 47 | } 48 | }, 49 | "types": "./dist/index.d.ts", 50 | "main": "./dist/index.js", 51 | "bin": { 52 | "ocular-bootstrap": "./scripts/bootstrap.js", 53 | "ocular-build": "./scripts/build.js", 54 | "ocular-bundle": "./scripts/bundle.js", 55 | "ocular-bump": "./scripts/bump.js", 56 | "ocular-clean": "./scripts/clean.js", 57 | "ocular-lint": "./scripts/lint.js", 58 | "ocular-metrics": "./scripts/metrics.js", 59 | "ocular-publish": "./scripts/publish.js", 60 | "ocular-test": "./scripts/test.js" 61 | }, 62 | "scripts": { 63 | "build": "(cd ../.. && ocular-build)", 64 | "publish-prod": "npm run build && npm publish", 65 | "publish-beta": "npm run build && npm publish --tag beta" 66 | }, 67 | "dependencies": { 68 | "@babel/cli": "^7.14.5", 69 | "@babel/core": "^7.14.5", 70 | "@babel/eslint-parser": "^7.14.5", 71 | "@babel/plugin-transform-runtime": "^7.14.5", 72 | "@babel/preset-env": "^7.14.5", 73 | "@babel/preset-react": "^7.14.5", 74 | "@babel/preset-typescript": "^7.14.5", 75 | "@babel/runtime": "7.14.5", 76 | "@esbuild-plugins/node-globals-polyfill": "^0.2.0", 77 | "@esbuild-plugins/node-modules-polyfill": "^0.2.0", 78 | "@probe.gl/test-utils": "^4.0.6", 79 | "@typescript-eslint/eslint-plugin": "^6.14.0", 80 | "@typescript-eslint/parser": "^6.14.0", 81 | "babel-plugin-version-inline": "^1.0.0", 82 | "c8": "^7.12.0", 83 | "coveralls": "^3.0.3", 84 | "deepmerge": "^4.2.2", 85 | "esbuild": "^0.16.7", 86 | "esbuild-plugin-external-global": "^1.0.1", 87 | "eslint": "^8.52.0", 88 | "eslint-config-prettier": "^6.7.0", 89 | "eslint-plugin-babel": "^5.3.1", 90 | "eslint-plugin-import": "^2.28.0", 91 | "eslint-plugin-jsx-a11y": "^6.1.2", 92 | "eslint-plugin-markdown": "^2.2.0", 93 | "eslint-plugin-react": "^7.22.0", 94 | "eslint-plugin-react-hooks": "^4.0.0", 95 | "glob": "^7.1.4", 96 | "lerna": "^3.14.1", 97 | "minimatch": "^3.0.0", 98 | "prettier": "3.0.3", 99 | "prettier-check": "2.0.0", 100 | "tape": "^4.11.0", 101 | "tape-promise": "^4.0.0", 102 | "typescript": "^5.2.2", 103 | "ts-node": "~10.9.0", 104 | "ts-patch": "^3.1.2", 105 | "tsconfig-paths": "^4.1.1", 106 | "vite": "^4.5.0" 107 | }, 108 | "devDependencies": { 109 | "puppeteer": "^22.0.0" 110 | }, 111 | "engines": { 112 | "node": ">= 18" 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /docs/table-of-contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "table-of-contents", 3 | "chapters": [ 4 | { 5 | "title": "Overview", 6 | "entries": [ 7 | { 8 | "entry": "docs" 9 | } 10 | ] 11 | }, 12 | { 13 | "title": "ocular-dev-tools", 14 | "chapters": [ 15 | { 16 | "title": "Overview", 17 | "entries": [ 18 | { 19 | "entry": "modules/dev-tools/docs/" 20 | }, 21 | { 22 | "entry": "modules/dev-tools/docs/whats-new" 23 | }, 24 | { 25 | "entry": "modules/dev-tools/docs/upgrade-guide" 26 | }, 27 | { 28 | "entry": "modules/dev-tools/docs/faq" 29 | } 30 | ] 31 | }, 32 | { 33 | "title": "Configuration Guide", 34 | "entries": [ 35 | { 36 | "entry": "modules/dev-tools/docs/" 37 | }, 38 | { 39 | "entry": "modules/dev-tools/docs/developer-guide/command-line-interface" 40 | }, 41 | { 42 | "entry": "modules/dev-tools/docs/developer-guide/configuring-tests" 43 | }, 44 | { 45 | "entry": "modules/dev-tools/docs/developer-guide/aliases" 46 | } 47 | ] 48 | }, 49 | { 50 | "title": "Command Line Reference", 51 | "entries": [ 52 | { 53 | "entry": "modules/dev-tools/docs/cli/ocular-bootstrap" 54 | }, 55 | { 56 | "entry": "modules/dev-tools/docs/cli/ocular-build" 57 | }, 58 | { 59 | "entry": "modules/dev-tools/docs/cli/ocular-clean" 60 | }, 61 | { 62 | "entry": "modules/dev-tools/docs/cli/ocular-lint" 63 | }, 64 | { 65 | "entry": "modules/dev-tools/docs/cli/ocular-metrics" 66 | }, 67 | { 68 | "entry": "modules/dev-tools/docs/cli/ocular-publish" 69 | }, 70 | { 71 | "entry": "modules/dev-tools/docs/cli/ocular-test" 72 | }, 73 | { 74 | "entry": "modules/dev-tools/docs/cli/ocular-bump" 75 | } 76 | ] 77 | }, 78 | { 79 | "title": "API Reference", 80 | "entries": [ 81 | { 82 | "entry": "modules/dev-tools/docs/api-reference/get-babel-config" 83 | }, 84 | { 85 | "entry": "modules/dev-tools/docs/api-reference/get-eslint-config" 86 | }, 87 | { 88 | "entry": "modules/dev-tools/docs/api-reference/get-prettier-config" 89 | }, 90 | { 91 | "entry": "modules/dev-tools/docs/api-reference/get-webpack-config" 92 | } 93 | ] 94 | } 95 | ] 96 | }, 97 | { 98 | "title": "gatsby-theme-ocular", 99 | "chapters": [ 100 | { 101 | "title": "Overview", 102 | "entries": [ 103 | { 104 | "entry": "modules/gatsby-theme-ocular/docs" 105 | }, 106 | { 107 | "entry": "modules/gatsby-theme-ocular/docs/get-started" 108 | }, 109 | { 110 | "entry": "modules/gatsby-theme-ocular/docs/whats-new" 111 | }, 112 | { 113 | "entry": "modules/gatsby-theme-ocular/docs/upgrade-guide" 114 | } 115 | ] 116 | }, 117 | { 118 | "title": "Creating content", 119 | "entries": [ 120 | { 121 | "entry": "modules/gatsby-theme-ocular/docs" 122 | }, 123 | { 124 | "entry": "modules/gatsby-theme-ocular/docs/get-started" 125 | }, 126 | { 127 | "entry": "modules/gatsby-theme-ocular/docs/whats-new" 128 | }, 129 | { 130 | "entry": "modules/gatsby-theme-ocular/docs/upgrade-guide" 131 | } 132 | ] 133 | }, 134 | { 135 | "title": "Creating content", 136 | "entries": [ 137 | { 138 | "entry": "modules/gatsby-theme-ocular/docs/creating-content/writing-documentation" 139 | }, 140 | { 141 | "entry": "modules/gatsby-theme-ocular/docs/creating-content/interactive-examples" 142 | } 143 | ] 144 | }, 145 | { 146 | "title": "Developer Guide", 147 | "entries": [ 148 | { 149 | "entry": "modules/gatsby-theme-ocular/docs/developer-guide/configuring" 150 | }, 151 | { 152 | "entry": "modules/gatsby-theme-ocular/docs/developer-guide/deploying" 153 | }, 154 | { 155 | "entry": "modules/gatsby-theme-ocular/docs/developer-guide/debugging" 156 | } 157 | ] 158 | }, 159 | { 160 | "title": "API Reference", 161 | "entries": [ 162 | { 163 | "entry": "modules/gatsby-theme-ocular/docs/api-reference/options" 164 | }, 165 | { 166 | "entry": "modules/gatsby-theme-ocular/docs/api-reference/generated-pages" 167 | } 168 | ] 169 | } 170 | ] 171 | } 172 | ] 173 | } 174 | -------------------------------------------------------------------------------- /website/static/images/icon-react.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | react 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/get-esbuild-config.ts: -------------------------------------------------------------------------------- 1 | // / For bundles published to npm 2 | import fs from 'fs'; 3 | import {join} from 'path'; 4 | import util from 'util'; 5 | import {getOcularConfig} from '../helpers/get-ocular-config.js'; 6 | import ext from 'esbuild-plugin-external-global'; 7 | import type {BuildOptions} from 'esbuild'; 8 | 9 | /** 10 | * Get list of dependencies to exclude using esbuild-plugin-external-global 11 | * @param externalPackages string[] 12 | */ 13 | // function getExternalGlobalsAMD(externalPackages) { 14 | // const externals = {}; 15 | // for (const packageName of externalPackages) { 16 | // externals[packageName] = `typeof require === 'function' ? require('${packageName}') : null`; 17 | // } 18 | // return externals; 19 | // } 20 | 21 | /** 22 | * Get list of dependencies to exclude using esbuild-plugin-external-global 23 | * @param externalPackages string[] 24 | * @param mapping {[pattern: string]: replacement} 25 | */ 26 | function getExternalGlobalsIIFE(externalPackages: string[], mapping: Record) { 27 | const externals: Record = {}; 28 | for (const packageName of externalPackages) { 29 | for (const key in mapping) { 30 | if (packageName.search(key) === 0) { 31 | externals[packageName] = mapping[key]; 32 | break; 33 | } 34 | } 35 | } 36 | return externals; 37 | } 38 | 39 | // esbuild does not support umd format 40 | // Work around from https://github.com/evanw/esbuild/issues/819 41 | // Template: https://webpack.js.org/configuration/output/#type-umd 42 | function umdWrapper(libName: string | undefined) { 43 | return { 44 | format: 'iife', 45 | globalName: '__exports__', 46 | banner: { 47 | js: `\ 48 | (function webpackUniversalModuleDefinition(root, factory) { 49 | if (typeof exports === 'object' && typeof module === 'object') 50 | module.exports = factory(); 51 | else if (typeof define === 'function' && define.amd) define([], factory); 52 | ${ 53 | libName 54 | ? `else if (typeof exports === 'object') exports['${libName}'] = factory(); 55 | else root['${libName}'] = factory();` 56 | : `else { 57 | var a = factory(); 58 | for (var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; 59 | }` 60 | }})(globalThis, function () {` 61 | }, 62 | footer: { 63 | js: `\ 64 | return __exports__; 65 | });` 66 | } 67 | }; 68 | } 69 | 70 | /** Returns esbuild config for building .cjs bundles */ 71 | export async function getCJSExportConfig(opts: { 72 | input: string; 73 | output: string; 74 | }): Promise { 75 | return { 76 | entryPoints: [opts.input], 77 | outfile: opts.output, 78 | bundle: true, 79 | format: 'cjs', 80 | // Node 16 is out of support, kept for compatibility. Move to 18? 81 | target: 'node16', 82 | packages: 'external', 83 | sourcemap: true, 84 | logLevel: 'info' 85 | }; 86 | } 87 | 88 | type BundleOptions = { 89 | input: string; 90 | env?: 'dev' | 'prod'; 91 | output?: string; 92 | format?: 'iife' | 'cjs' | 'esm' | 'umd'; 93 | target?: string[]; 94 | externals?: string[]; 95 | globalName?: string; 96 | globals?: {[pattern: string]: string}; 97 | debug?: boolean; 98 | sourcemap?: boolean; 99 | }; 100 | 101 | /* eslint-disable max-statements,complexity */ 102 | /** Returns esbuild config for building standalone bundles */ 103 | export async function getBundleConfig(opts: BundleOptions): Promise { 104 | // This script must be executed in a submodule's directory 105 | const packageRoot = process.cwd(); 106 | const packageInfo = JSON.parse(fs.readFileSync(join(packageRoot, 'package.json'), 'utf-8')); 107 | 108 | const devMode = opts.env === 'dev'; 109 | 110 | const ocularConfig = await getOcularConfig({ 111 | root: join(packageRoot, '../..'), 112 | aliasMode: devMode ? 'src' : 'dist' 113 | }); 114 | 115 | opts = {...ocularConfig.bundle, ...opts}; 116 | 117 | const { 118 | input, 119 | output = devMode ? './dist/dist.dev.js' : './dist.min.js', 120 | format = 'iife', 121 | target = ['esnext'], 122 | externals, 123 | globalName, 124 | debug, 125 | sourcemap = false 126 | } = opts; 127 | 128 | let babelConfig; 129 | 130 | let externalPackages = Object.keys(packageInfo.peerDependencies || {}); 131 | if (typeof externals === 'string') { 132 | externalPackages = externalPackages.concat((externals as string).split(',')); 133 | } else if (Array.isArray(externals)) { 134 | externalPackages = externalPackages.concat(externals); 135 | } 136 | 137 | const config: BuildOptions = { 138 | entryPoints: [input], 139 | outfile: output, 140 | bundle: true, 141 | // @ts-expect-error umd is not supported by esbuild, will be overwritten below 142 | format, 143 | minify: !devMode, 144 | alias: ocularConfig.aliases, 145 | platform: 'browser', 146 | target, 147 | logLevel: 'info', 148 | sourcemap, 149 | plugins: [] 150 | }; 151 | if (globalName) { 152 | config.globalName = globalName; 153 | } 154 | 155 | let externalGlobals; 156 | switch (format) { 157 | case 'cjs': 158 | case 'esm': 159 | // Use esbuild's built-in external functionality 160 | config.packages = 'external'; 161 | if (externals) { 162 | config.external = externals; 163 | } 164 | break; 165 | 166 | case 'umd': 167 | Object.assign(config, umdWrapper(globalName)); 168 | externalGlobals = getExternalGlobalsIIFE(externalPackages, ocularConfig.bundle.globals); 169 | break; 170 | 171 | case 'iife': 172 | externalGlobals = getExternalGlobalsIIFE(externalPackages, ocularConfig.bundle.globals); 173 | break; 174 | 175 | default: 176 | break; 177 | } 178 | if (externalGlobals) { 179 | config.plugins!.unshift(ext.externalGlobalPlugin(externalGlobals)); 180 | } 181 | 182 | if (debug) { 183 | const printableConfig = { 184 | ...config, 185 | plugins: config.plugins!.map((item) => { 186 | return { 187 | name: item.name, 188 | options: item.name === 'babel' ? babelConfig : externalGlobals 189 | }; 190 | }) 191 | }; 192 | 193 | console.log(util.inspect(printableConfig, {showHidden: false, depth: null, colors: true})); 194 | } 195 | 196 | return config; 197 | } 198 | -------------------------------------------------------------------------------- /modules/dev-tools/src/helpers/get-ocular-config.ts: -------------------------------------------------------------------------------- 1 | /* @typedef {import('./get-ocular-config')} default */ 2 | 3 | import fs from 'fs'; 4 | import {resolve} from 'path'; 5 | import getAliases, {getModuleInfo} from './aliases.js'; 6 | import {shallowMerge, getValidPath, ocularRoot} from '../utils/utils.js'; 7 | import type {BrowserTestDriver} from '@probe.gl/test-utils'; 8 | 9 | // TODO - export from probe.gl 10 | type BrowserTestOptions = Parameters[0]; 11 | 12 | /** User configuration from .ocularrc.js */ 13 | export type OcularConfig = { 14 | root?: string; 15 | 16 | esm?: boolean; 17 | 18 | aliases?: {[module: string]: string}; 19 | 20 | nodeAliases?: {[module: string]: string}; 21 | 22 | babel?: 23 | | { 24 | configPath?: string; 25 | extensions?: string[]; 26 | } 27 | | false; 28 | 29 | bundle?: { 30 | target?: string[]; 31 | globalName?: string; 32 | format?: 'cjs' | 'esm' | 'umd' | 'iife'; 33 | externals?: string[]; 34 | globals?: {[pattern: string]: string}; 35 | }; 36 | 37 | typescript?: { 38 | project: string; 39 | }; 40 | 41 | lint?: { 42 | paths?: string[]; 43 | extensions?: string[]; 44 | }; 45 | 46 | vite?: { 47 | version?: number; 48 | configPath?: string; 49 | }; 50 | 51 | coverage?: { 52 | test?: 'node' | 'browser'; 53 | }; 54 | 55 | browserTest?: { 56 | server?: BrowserTestOptions['server']; 57 | browser?: BrowserTestOptions['browser']; 58 | }; 59 | 60 | entry?: { 61 | test?: string; 62 | 'test-browser'?: `${string}.html`; 63 | bench?: string; 64 | 'bench-browser'?: `${string}.html`; 65 | size?: string[] | string; 66 | }; 67 | }; 68 | 69 | /** Internal type to typecheck resolved ocular config inside ocular-dev-tools */ 70 | export type MaterializedOcularConfig = { 71 | root: string; 72 | ocularPath: string; 73 | esm: boolean; 74 | 75 | aliases: {[module: string]: string}; 76 | 77 | babel: 78 | | { 79 | configPath: string; 80 | extensions: string[]; 81 | } 82 | | false; 83 | 84 | bundle: { 85 | target?: string[]; 86 | globalName?: string; 87 | format?: 'cjs' | 'esm' | 'umd' | 'iife'; 88 | externals?: string[]; 89 | globals: {[pattern: string]: string}; 90 | }; 91 | 92 | typescript: { 93 | project: string; 94 | }; 95 | 96 | lint: { 97 | paths: string[]; 98 | extensions: string[]; 99 | }; 100 | 101 | vite: { 102 | version: number; 103 | configPath: string; 104 | }; 105 | 106 | coverage: { 107 | test: 'node' | 'browser'; 108 | }; 109 | 110 | browserTest?: { 111 | server?: BrowserTestOptions['server']; 112 | browser?: BrowserTestOptions['browser']; 113 | }; 114 | 115 | entry: { 116 | test: string; 117 | 'test-browser': `${string}.html`; 118 | bench: string; 119 | 'bench-browser': `${string}.html`; 120 | size: string[]; 121 | }; 122 | }; 123 | 124 | export async function getOcularConfig( 125 | options: { 126 | root?: string; 127 | aliasMode?: string; 128 | } = {} 129 | ): Promise { 130 | const packageRoot = options.root || process.env.PWD!; 131 | 132 | const IS_MONOREPO = fs.existsSync(resolve(packageRoot, './modules')); 133 | 134 | const userConfig = await getUserConfig(packageRoot); 135 | 136 | const config: MaterializedOcularConfig = { 137 | root: packageRoot, 138 | ocularPath: ocularRoot, 139 | 140 | esm: getModuleInfo(packageRoot)?.packageInfo.type === 'module', 141 | 142 | babel: 143 | userConfig.babel !== false 144 | ? { 145 | configPath: getValidPath( 146 | resolve(packageRoot, './.babelrc'), 147 | resolve(packageRoot, './.babelrc.js'), 148 | resolve(packageRoot, './.babelrc.cjs'), 149 | resolve(packageRoot, './babel.config.js'), 150 | resolve(packageRoot, './babel.config.cjs') 151 | )!, 152 | extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx'] 153 | } 154 | : false, 155 | 156 | bundle: { 157 | globals: {} 158 | }, 159 | 160 | typescript: { 161 | project: '' 162 | }, 163 | 164 | lint: { 165 | paths: IS_MONOREPO ? ['modules'] : ['src'], 166 | extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx', 'd.ts'] 167 | }, 168 | 169 | coverage: { 170 | test: 'node' 171 | }, 172 | 173 | aliases: {}, 174 | 175 | entry: { 176 | test: 'test/index.ts', 177 | 'test-browser': 'test/index.html', 178 | bench: 'test/bench/index.ts', 179 | 'bench-browser': 'test/bench/index.html', 180 | size: ['test/size.ts'] 181 | }, 182 | 183 | vite: { 184 | version: 4, 185 | configPath: getValidPath( 186 | resolve(packageRoot, './vite.config.js'), 187 | resolve(packageRoot, './vite.config.cjs'), 188 | resolve(ocularRoot, 'dist/configuration/vite.config.js') 189 | )! 190 | } 191 | }; 192 | 193 | shallowMerge(config, userConfig); 194 | 195 | // Backward compatibility 196 | if (typeof userConfig.entry?.size === 'string') { 197 | userConfig.entry.size = [userConfig.entry.size]; 198 | } 199 | 200 | const aliasMode = options.aliasMode || 'src'; 201 | 202 | // User's aliases need to come first, due to module-alias resolve order 203 | Object.assign(config.aliases, getAliases(aliasMode, packageRoot)); 204 | 205 | if (aliasMode && !aliasMode.includes('browser')) { 206 | Object.assign(config.aliases, userConfig.nodeAliases); 207 | } 208 | 209 | return config; 210 | } 211 | 212 | // HELPERS 213 | 214 | /** 215 | * TODO better error messages 216 | */ 217 | async function getUserConfig(packageRoot: string): Promise { 218 | const userConfigPath = getValidPath( 219 | resolve(packageRoot, './.ocularrc.js'), 220 | resolve(packageRoot, './.ocularrc.cjs'), 221 | resolve(packageRoot, './.ocular.config.js'), 222 | resolve(packageRoot, './.ocular.config.cjs'), 223 | // deprecated 224 | resolve(packageRoot, './ocular-dev-tools.config.js') 225 | ); 226 | 227 | if (userConfigPath) { 228 | const userConfigModule = (await import(userConfigPath)) as 229 | | OcularConfig 230 | | {default: OcularConfig}; 231 | if ('default' in userConfigModule) { 232 | return userConfigModule.default; 233 | } 234 | return userConfigModule; 235 | } 236 | 237 | throw new Error('No valid user config found'); 238 | } 239 | -------------------------------------------------------------------------------- /modules/dev-tools/src/test.ts: -------------------------------------------------------------------------------- 1 | // Launch script for various Node test configurations 2 | import fs from 'fs'; 3 | import {resolve} from 'path'; 4 | import {execShellCommand} from './utils/utils.js'; 5 | 6 | import {getOcularConfig} from './helpers/get-ocular-config.js'; 7 | 8 | import {BrowserTestDriver} from '@probe.gl/test-utils'; 9 | import {createServer} from 'vite'; 10 | 11 | const mode = process.argv.length >= 3 ? process.argv[2] : 'default'; 12 | const ocularConfig = await getOcularConfig({aliasMode: mode}); 13 | const viteConfigPath = ocularConfig.vite.configPath; 14 | // c8 default directory for coverage data 15 | const CoverageTempDir = './coverage/tmp'; 16 | 17 | console.log(`Running ${mode} tests...`); // eslint-disable-line 18 | 19 | switch (mode) { 20 | case 'cover': 21 | if (ocularConfig.coverage.test === 'node') { 22 | runNodeTest(resolveNodeEntry('test'), 'npx c8'); 23 | } else { 24 | await runBrowserTest({ 25 | server: { 26 | start: createViteServer, 27 | options: { 28 | mode: 'test' 29 | } 30 | }, 31 | url: resolveBrowserEntry('test'), 32 | headless: 'new', 33 | onStart: async ({page}) => { 34 | clearCoverage(); 35 | await page.coverage.startJSCoverage({includeRawScriptCoverage: true}); 36 | }, 37 | onFinish: async ({page, isSuccessful}) => { 38 | const coverage = await page.coverage.stopJSCoverage(); 39 | if (!isSuccessful) return; 40 | writeCoverage(coverage); 41 | } 42 | }); 43 | } 44 | break; 45 | 46 | case 'node': 47 | case 'dist': 48 | runNodeTest(resolveNodeEntry('test')); // Run the tests 49 | break; 50 | 51 | case 'bench': 52 | runNodeTest(resolveNodeEntry('bench')); // Run the benchmarks 53 | break; 54 | 55 | case 'browser': 56 | case 'browser-headless': 57 | await runBrowserTest({ 58 | server: { 59 | start: createViteServer, 60 | options: { 61 | mode: 'test' 62 | } 63 | }, 64 | url: resolveBrowserEntry('test'), 65 | headless: mode === 'browser-headless' ? 'new' : false 66 | }); 67 | break; 68 | 69 | default: 70 | if (/\bbrowser\b/.test(mode)) { 71 | const testMode = mode.replace('-browser', '').replace('-headless', ''); 72 | await runBrowserTest({ 73 | server: { 74 | start: createViteServer, 75 | options: { 76 | mode: testMode 77 | } 78 | }, 79 | url: resolveBrowserEntry(testMode), 80 | headless: /\bheadless\b/.test(mode) ? 'new' : false 81 | }); 82 | } else if (mode in ocularConfig.entry) { 83 | runNodeTest(resolveNodeEntry(mode)); 84 | } else { 85 | throw new Error(`Unknown test mode ${mode}`); 86 | } 87 | } 88 | 89 | function resolveNodeEntry(key: string): string { 90 | const entry = ocularConfig.entry[key]; 91 | if (typeof entry === 'string') { 92 | return resolve(entry); 93 | } 94 | throw new Error(`Cannot find entry point ${key} in ocular config.`); 95 | } 96 | 97 | function resolveBrowserEntry(key: string): string { 98 | const fileName = ocularConfig.entry[`${key}-browser`]; 99 | if (typeof fileName === 'string' && fileName.endsWith('.html')) { 100 | return fileName; 101 | } else if (fileName) { 102 | return 'index.html'; 103 | } 104 | throw new Error(`Cannot find entry point ${key}-browser in ocular config.`); 105 | } 106 | 107 | function runNodeTest(entry: string, command: string = '') { 108 | // Save module alias 109 | fs.writeFileSync( 110 | resolve(ocularConfig.ocularPath, '.alias.json'), 111 | JSON.stringify(ocularConfig.aliases) 112 | ); 113 | 114 | if (ocularConfig.esm) { 115 | execShellCommand( 116 | `NODE_OPTIONS="--experimental-modules --es-module-specifier-resolution=node --loader ${ocularConfig.ocularPath}/dist/helpers/esm-loader.js" ${command} node "${entry}"` 117 | ); 118 | } else { 119 | execShellCommand( 120 | `${command} ts-node -r "${ocularConfig.ocularPath}/dist/helpers/cjs-register.cjs" "${entry}"` 121 | ); 122 | } 123 | } 124 | 125 | function runBrowserTest(opts) { 126 | const userConfig = ocularConfig.browserTest || {}; 127 | return new BrowserTestDriver().run({ 128 | ...opts, 129 | ...userConfig, 130 | server: {...opts.server, ...userConfig.server}, 131 | browser: {...opts.browser, ...userConfig.browser} 132 | }); 133 | } 134 | 135 | async function createViteServer(config) { 136 | const server = await createServer({ 137 | configFile: viteConfigPath, 138 | mode: config.options?.mode, 139 | server: { 140 | port: config.port 141 | } 142 | }); 143 | await server.listen(); 144 | 145 | return { 146 | url: server.resolvedUrls?.local[0], 147 | stop: () => { 148 | server.close(); 149 | } 150 | }; 151 | } 152 | 153 | function clearCoverage() { 154 | fs.rmSync(CoverageTempDir, {force: true, recursive: true}); 155 | fs.mkdirSync(CoverageTempDir, {recursive: true}); 156 | } 157 | 158 | /** Write raw coverage data to disk for c8 to report */ 159 | function writeCoverage(coverage) { 160 | const outputFile = `${CoverageTempDir}/coverage-${Date.now()}`; 161 | 162 | // Convert Chrome coverage format to v8 163 | let idx = 0; 164 | for (const cov of coverage) { 165 | const it = cov.rawScriptCoverage; 166 | const filePath = it.url.replace(/^http:\/\/localhost:\d+\//, ''); 167 | 168 | // Excluded directories 169 | if (filePath.match(/(^|\/)(node_modules|test|@vite)\//)) continue; 170 | // Remap file url to path on local disk 171 | const fileUrl = `file://${resolve(filePath)}`; 172 | it.url = fileUrl; 173 | 174 | const sourcemapCache = {}; 175 | const [generatedSource, sourcemapDataUrl] = cov.text.split(/\/\/# sourceMappingURL=/); 176 | if (sourcemapDataUrl) { 177 | // Save source mapping for c8 reporter 178 | sourcemapCache[fileUrl] = { 179 | lineLengths: generatedSource.split('\n').map((l) => l.length), 180 | data: sourcemapFromDataUrl(sourcemapDataUrl) 181 | }; 182 | } 183 | 184 | fs.writeFileSync( 185 | `${outputFile}-${idx++}.json`, 186 | JSON.stringify({ 187 | result: [it], 188 | 'source-map-cache': sourcemapCache 189 | }), 190 | 'utf8' 191 | ); 192 | } 193 | 194 | // Print coverage to console 195 | execShellCommand('npx c8 report --reporter=text'); 196 | } 197 | 198 | function sourcemapFromDataUrl(url: string): string | null { 199 | const [format, data] = url.split(','); 200 | const base64 = format.endsWith('base64'); 201 | const decodedData = base64 ? Buffer.from(data, 'base64').toString('utf8') : data; 202 | try { 203 | return JSON.parse(decodedData); 204 | } catch (err) { 205 | return null; 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /modules/dev-tools/src/configuration/get-eslint-config.ts: -------------------------------------------------------------------------------- 1 | import eslint from '@typescript-eslint/eslint-plugin'; 2 | import deepMerge from 'deepmerge'; 3 | import {getValidPath, ocularRoot} from '../utils/utils.js'; 4 | import {inspect} from 'util'; 5 | import {resolve} from 'path'; 6 | 7 | const typescriptConfigs = eslint.configs; 8 | const localRules = (path) => resolve(ocularRoot, 'src/configuration', path); 9 | 10 | const DEFAULT_OPTIONS = { 11 | react: false 12 | } as const; 13 | 14 | const DEFAULT_CONFIG = { 15 | extends: [ 16 | localRules('./eslint-config-uber-es2015/eslintrc.json'), 17 | 'prettier', 18 | 'prettier/react', 19 | 'plugin:import/errors' 20 | ], 21 | plugins: ['import'], 22 | parser: '@babel/eslint-parser', 23 | parserOptions: { 24 | ecmaVersion: 2020, 25 | // @babel/eslint-parser issues https://github.com/babel/babel/issues/11975 26 | requireConfigFile: false, 27 | babelOptions: { 28 | configFile: getValidPath( 29 | './.babelrc', 30 | './.babelrc.js', 31 | './.babelrc.cjs', 32 | './babel.config.js', 33 | './babel.config.cjs' 34 | ) 35 | } 36 | }, 37 | env: { 38 | // Note: also sets ecmaVersion 39 | es2020: true 40 | }, 41 | globals: { 42 | globalThis: 'readonly', 43 | __VERSION__: 'readonly' 44 | }, 45 | rules: { 46 | 'guard-for-in': 0, 47 | 'generator-star-spacing': 0, 48 | 'func-names': 0, 49 | 'no-inline-comments': 0, 50 | 'no-multi-str': 0, 51 | 'space-before-function-paren': 0, 52 | 'accessor-pairs': ['error', {getWithoutSet: false, setWithoutGet: false}], 53 | 'import/no-unresolved': ['error'], 54 | 'import/no-extraneous-dependencies': ['error', {devDependencies: false, peerDependencies: true}] 55 | }, 56 | settings: { 57 | // Ensure eslint finds typescript files 58 | 'import/resolver': { 59 | node: { 60 | extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx', '.d.ts'] 61 | } 62 | } 63 | }, 64 | ignorePatterns: ['node_modules', '**/dist*/**/*.js'], 65 | overrides: [ 66 | { 67 | // babel-eslint can process TS files, but it doesn't understand types 68 | // typescript-eslint has some more advanced rules with type checking 69 | files: ['**/*.ts', '**/*.tsx', '**/*.d.ts'], 70 | parser: '@typescript-eslint/parser', 71 | parserOptions: { 72 | sourceType: 'module', // we want to use ES modules 73 | project: './tsconfig.json' 74 | }, 75 | plugins: ['@typescript-eslint'], 76 | rules: { 77 | ...typescriptConfigs['eslint-recommended'].rules, 78 | ...typescriptConfigs.recommended.rules, 79 | ...typescriptConfigs['recommended-requiring-type-checking'].rules, 80 | 81 | // typescript-eslint 6.0 82 | '@typescript-eslint/no-unsafe-argument': 0, 83 | '@typescript-eslint/no-redundant-type-constituents': 0, 84 | '@typescript-eslint/no-unsafe-enum-comparison': 1, 85 | '@typescript-eslint/no-duplicate-type-constituents': 1, 86 | '@typescript-eslint/no-base-to-string': 1, 87 | '@typescript-eslint/no-loss-of-precision': 1, 88 | 89 | // We still have some issues with import resolution 90 | 'import/named': 0, 91 | 'import/no-extraneous-dependencies': ['warn'], 92 | // Warn instead of error 93 | 'max-params': ['warn'], 94 | 'no-undef': ['warn'], 95 | camelcase: ['warn'], 96 | indent: ['warn', 2, {SwitchCase: 1}], 97 | quotes: ['warn', 'single'], 98 | 'no-process-env': 'off', 99 | 100 | // typescript rules 101 | 102 | // Some of JS rules don't always work correctly in TS and 103 | // hence need to be reimported as TS rules 104 | 'no-redeclare': 'off', 105 | 'no-shadow': 'off', 106 | 'no-use-before-define': 'off', 107 | 'no-dupe-class-members': 'off', 108 | 109 | // TODO - These rules are sometimes not found? 110 | // '@typescript-eslint/no-shadow': ['warn'], 111 | // '@typescript-eslint/no-redeclare': ['warn'], 112 | 113 | // We use function hoisting to put exports at top of file 114 | '@typescript-eslint/no-use-before-define': 'off', 115 | '@typescript-eslint/no-dupe-class-members': ['error'], 116 | 117 | // We encourage explicit typing, e.g `field: string = ''` 118 | '@typescript-eslint/no-inferrable-types': 'off', 119 | 120 | '@typescript-eslint/no-empty-interface': ['warn'], 121 | '@typescript-eslint/restrict-template-expressions': ['warn'], 122 | '@typescript-eslint/explicit-module-boundary-types': ['warn'], 123 | '@typescript-eslint/require-await': ['warn'], 124 | '@typescript-eslint/no-unsafe-return': ['warn'], 125 | '@typescript-eslint/no-unsafe-call': ['warn'], 126 | 127 | // some day we will hopefully be able to enable this rule 128 | '@typescript-eslint/no-explicit-any': 'off', 129 | '@typescript-eslint/ban-ts-comment': ['warn'], 130 | '@typescript-eslint/ban-types': ['warn'], 131 | '@typescript-eslint/no-unsafe-member-access': ['warn'], 132 | '@typescript-eslint/no-unsafe-assignment': ['warn'], 133 | '@typescript-eslint/no-var-requires': ['warn'], 134 | '@typescript-eslint/no-unused-vars': ['warn'], 135 | '@typescript-eslint/switch-exhaustiveness-check': ['error'], 136 | '@typescript-eslint/no-floating-promises': ['warn'], 137 | '@typescript-eslint/await-thenable': ['warn'], 138 | '@typescript-eslint/no-misused-promises': ['warn'], 139 | '@typescript-eslint/restrict-plus-operands': ['warn'], 140 | '@typescript-eslint/no-empty-function': ['warn'] 141 | } 142 | }, 143 | { 144 | // We can lint through code examples in Markdown as well, 145 | // but we don't need to enable all of the rules there 146 | files: ['**/*.md'], 147 | plugins: ['markdown'], 148 | // extends: 'plugin:markdown/recommended', 149 | rules: { 150 | 'no-undef': 'off', 151 | 'no-unused-vars': 'off', 152 | 'no-unused-expressions': 'off', 153 | 'no-console': 'off', 154 | 'padded-blocks': 'off' 155 | } 156 | } 157 | ] 158 | }; 159 | 160 | function getReactConfig(options) { 161 | return { 162 | extends: [ 163 | localRules('./eslint-config-uber-jsx/eslintrc.json'), 164 | 'prettier', 165 | 'prettier/react', 166 | 'plugin:import/errors' 167 | ], 168 | plugins: ['import', 'react'], 169 | settings: { 170 | react: { 171 | version: options.react 172 | } 173 | } 174 | }; 175 | } 176 | 177 | export function getESLintConfig( 178 | options: {react?: string | false; overrides?: any; debug?: boolean} = {} 179 | ) { 180 | options = {...DEFAULT_OPTIONS, ...options}; 181 | 182 | let config = {...DEFAULT_CONFIG}; 183 | if (options.react) { 184 | config = deepMerge(config, getReactConfig(options)); 185 | } 186 | if (options.overrides) { 187 | config = deepMerge(config, options.overrides); 188 | } 189 | if (options.debug) { 190 | // eslint-disable-next-line 191 | console.log(inspect(config, {colors: true, depth: null})); 192 | } 193 | 194 | return config; 195 | } 196 | -------------------------------------------------------------------------------- /modules/dev-tools/docs/README.md: -------------------------------------------------------------------------------- 1 | # ocular-dev-tools 2 | 3 | Dev tools for vis.gl open source Javascript frameworks 4 | 5 | Contains developer targets for building, cleaning, linting, testing and publishing frameworks. 6 | 7 | * The testing script has a number of modes, it can run tests on both browser and node, it can run test on src or built distributions etc. 8 | * The linting feature supports both code and markdown, and runs both eslint and prettier. 9 | * Supports both single module repos (all code in src) and monorepos (code in `modules//src`). 10 | 11 | Note: flow is not currently integrated into ocular-dev-tools as we restrict its use to React related code bases. 12 | 13 | ## Covered tools 14 | 15 | ocular installs the necessary dependencies and provides working default configurations for 16 | 17 | - eslint 18 | - prettier 19 | - ts-node 20 | - vite 21 | 22 | Note that this list may grow over time. 23 | 24 | ## Installation 25 | 26 | ```bash 27 | yarn add ocular-dev-tools 28 | ``` 29 | 30 | Your `package.json` should looks something like: 31 | 32 | ```json 33 | "devDependencies": { 34 | "ocular-dev-tools": "^2.0.0-alpha", 35 | "puppeteer": "^22.0.0" 36 | } 37 | ``` 38 | 39 | After installing you can set up your build scripts in package.json as follows: 40 | 41 | ```json 42 | "scripts": { 43 | "bootstrap": "yarn & ocular-bootstrap", 44 | "build": "ocular-clean && ocular-build", 45 | "lint": "ocular-lint", 46 | "metrics": "ocular-metrics", 47 | "publish": "ocular-publish", 48 | "test": "ocular-test" 49 | }, 50 | ``` 51 | 52 | ## Usage 53 | 54 | ### Command Line Tools 55 | 56 | | Typical Build Script | Ocular Script | Description | 57 | | --- | --- | --- | 58 | | [`ocular-bootstrap`](docs/dev-tools/cli/ocular-bootstrap) | `bootstrap` | Install dependencies for monorepos | 59 | | [`ocular-clean`](docs/dev-tools/cli/ocular-clean) | `clean` | Remove all transpiled files in preparation for a new build. | 60 | | [`ocular-build`](docs/dev-tools/cli/ocular-build) | `build` | Transpile all modules. | 61 | | [`ocular-lint`](docs/dev-tools/cli/ocular-lint) | `lint` | Run eslint & prettier on the code base. | 62 | | [`ocular-test`](docs/dev-tools/cli/ocular-test) | `test` | Run tests. | 63 | | [`ocular-metrics`](docs/dev-tools/cli/ocular-metrics) | `metrics` | Bundle the source and report the bundle size. | 64 | | [`ocular-publish`](docs/dev-tools/cli/ocular-publish) | `publish` | Publish the packages, create git tag and push. | 65 | 66 | 67 | ### Configuration 68 | 69 | To provide maximum control to the user, ocular build scripts use config files in the framework repo. In cases where such files allow for importing other templates, ocular provides exports that can be used, if not it provides a template that the user can copy into the frameworks root directory. 70 | 71 | #### .ocularrc.js 72 | 73 | A file `.ocularrc.js` can be placed at the root of the package to customize the dev scripts. The config file may export a JSON object that contains the following keys, or a callback function that returns such object: 74 | 75 | - `esm` (Boolean) - set if tests should run using Node.js's ES module resolution. By default `true` if and only if `type: "module"` is found in the root package.json. 76 | - `lint` - options to control eslint behavior 77 | + `paths` (Arrray) - directories to include when linting. Default `['modules', 'src']` 78 | + `extensions` (Array) - file extensions to include when linting. Default `['js', 'md']` 79 | - `babel` - options to control babel behavior 80 | + `extensions` - List of file extensions (prefixed with `.`) that `babel` will process. Default `['.es6', '.js', '.es', '.jsx', '.mjs']` 81 | - `aliases` (Object) - Module aliases to use in tests. Any import from a submodule is mapped to its source. Use this object to define additional mappings, for example `"test-data": "./test/sample-data`. 82 | - `nodeAliases` (Object) - Module aliases to use in node tests only. 83 | - `typescript` 84 | + `project` (String) - path to the project's tsconfig 85 | - `bundle` - options to control esbuild behavior 86 | + `target` (String) 87 | + `globalName` (String) 88 | + `format` (String) - one of `cjs`, `esm`, `umd`, `iife` 89 | + `externals` (String[]) 90 | + `globals` (Object) - import package from global variable. 91 | - `entry` (Object) - entry points for tests. 92 | + `test` (String) - unit test entry point. Can be a `.js` or `.ts` file. Default `./test/index.ts`. 93 | + `test-browser` (String) - unit test browser entry point. Can be a `.js`, `.ts` or `.html` file. Default `./test/browser.ts`. 94 | + `bench` (String) - benchmark entry point. Can be a `.js` or `.ts` file. Default `./test/bench/index.ts`. 95 | + `bench-browser` (String) - benchmark browser entry point. Can be a `.js`, `.ts` or `.html` file. Default `./test/bench/browser.ts`. 96 | + `size` (String | String[]) - metrics entry point(s). Can be a `.js` or `.ts` file. Default `./test/size.ts`. 97 | - `browserTest` (Object) - options for browser tests. Passed to [BrowserTestDriver.run](https://uber-web.github.io/probe.gl/#/documentation/api-reference-testing/browsertestdriver). 98 | 99 | 100 | #### babel 101 | 102 | You may extend the default eslint config with a `.babelrc.js` or `babel.config.js` at the project root: 103 | 104 | ```js 105 | // .babelrc.js 106 | const {getBabelConfig} = require('ocular-dev-tools/configuration'); 107 | 108 | module.exports = getBabelConfig({ 109 | react: true, 110 | // specify custom configs 111 | overrides: { 112 | overrides: [ 113 | // babel overrides api 114 | ] 115 | } 116 | }); 117 | ``` 118 | 119 | #### eslint 120 | 121 | You may extend the default eslint config with a `.eslintrc.js` or `eslint.config.js` at the project root: 122 | 123 | ```js 124 | // .eslintrc.js 125 | const {getEslintConfig} = require('ocular-dev-tools/configuration'); 126 | 127 | module.exports = getEslintConfig({ 128 | react: '18.0', 129 | // specify custom configs 130 | overrides: {} 131 | }); 132 | ``` 133 | 134 | #### prettier 135 | 136 | You may extend the default eslint config with a `.prettier.js` or `prettier.config.js` at the project root: 137 | 138 | ```js 139 | // .prettier.js 140 | const {getPrettierConfig} = require('ocular-dev-tools/configuration'); 141 | 142 | module.exports = getPrettierConfig({ 143 | // specify custom configs 144 | overrides: {} 145 | }); 146 | ``` 147 | 148 | #### vite 149 | 150 | If `vite.config.js` is found at the root of the package, it is used to bundle units tests and benchmark tests for the browser. Otherwise, a default vite config is used. 151 | 152 | 153 | ## ESM Repo 154 | 155 | ocular-dev-tools v2.0 can be used in a ESM repo. When enabled, all imports/exports are handled with Node.js's native [ESM](https://nodejs.org/api/esm.html#introduction) support, instead of being transpiled to commonjs. 156 | 157 | To enable ESM mode: 158 | 159 | - Add `type: 'module'` to the root `package.json` and each submodule's `package.json`s. 160 | - Add `compilerOptions.module: 'esnext'` to `tsconfig.json`. 161 | - ES5-style `require()` and `module.exports` must be removed from all `.js` files. Some dev dependencies, for example babel and eslint, may not support ESM syntax. In this case, rename the config files to use the `.cjs` extension so that they can be imported successfully. 162 | - When importing directly from a non-TypeScript file, the file extension must be specified. E.g. `import './init'` now becomes `import './init.js'`. 163 | -------------------------------------------------------------------------------- /modules/dev-tools/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG (ocular-dev-tools) 2 | 3 | ## v2.0.0-alpha.29 4 | 5 | - fix(dev-tools): remove log prefix (#459) 6 | 7 | ## v2.0.0-alpha.28 8 | 9 | - Fix commands with yarn 4 (#457) 10 | 11 | ## v2.0.0-alpha.27 12 | 13 | - Add ts-transform-inline-webgl-constants (#456) 14 | 15 | ## v2.0.0-alpha.26 16 | 17 | - Fix coverage reporting format 18 | 19 | ## v2.0.0-alpha.25 20 | 21 | - Revert changes to headless mode 22 | 23 | ## v2.0.0-alpha.24 24 | 25 | - feat(dev-tools): add ts-transform-remove-glsl-comments (#455) 26 | - Add tests for TypeScript plugins (#452) 27 | - chore(dev-tools): clean up package.json (#454) 28 | - chore(test-utils): Migrate to typescript (#453) 29 | - Use ocular-build to build dev-tools (#451) 30 | - Add option to report code coverage against browser test (#450) 31 | - fix: prettier log level (#449) 32 | 33 | ## v2.0.0-alpha.23 34 | 35 | - Remove smoosh script (#448) 36 | - Remove puppeteer global install (#447) 37 | 38 | ## v2.0.0-alpha.21 39 | 40 | - ESM module build command improvements (#446) 41 | 42 | ## v2.0.0-alpha.20 43 | 44 | - Bump major versions of tooling: prettier to 3.x, eslint to 8.5.x, typescript to 5.2.2 (#437) 45 | 46 | ## v2.0.0-alpha.19 47 | 48 | - fix(dev-tools) use new headless mode in browser tests (#436) 49 | 50 | ## v2.0.0-alpha.18 51 | 52 | - bundle command always merges babel config (#435) 53 | 54 | ## v2.0.0-alpha.17 55 | 56 | - Add react support to dev bundle (#433) 57 | 58 | ## v2.0.0-alpha.16 59 | 60 | - Minor fix of ESM resolution (#431) 61 | - Change cjs entry point target (#432) 62 | 63 | ## v2.0.0-alpha.15 64 | 65 | - Support building esm module with multiple entry points (#430) 66 | 67 | ## v2.0.0-alpha.14 68 | 69 | - Update babel config for esm target (#429) 70 | 71 | ## v2.0.0-alpha.13 72 | 73 | - Fix metrics import 74 | 75 | ## v2.0.0-alpha.12 76 | 77 | - Start vite server from JS API (#424) 78 | 79 | ## v2.0.0-alpha.11 80 | 81 | - Set NODE_ENV during test 82 | 83 | ## v2.0.0-alpha.10 84 | 85 | - Bump esbuild plugins versions (#422) 86 | 87 | ## v2.0.0-alpha.9 88 | 89 | - Fix umd bundle settings (#420) 90 | 91 | ## v2.0.0-alpha.8 92 | 93 | - Fix test dist alias resolution (#418) 94 | 95 | ## v2.0.0-alpha.7 96 | 97 | - clean up dependencies (#416) 98 | - Remove shelljs (#415) 99 | 100 | ## v2.0.0-alpha.6 101 | 102 | - Add ocular-bundle command (#414) 103 | 104 | ## v2.0.0-alpha.5 105 | 106 | - Suppress commit hooks in lerna publish (#413) 107 | - Add Typescript build commands (#412) 108 | - eslintrc auto determine babel config path (#411) 109 | - Drop import assertion for better compatibility (#410) 110 | 111 | ## v2.0.0-alpha.4 112 | 113 | - support for ESM repos 114 | 115 | ## v2.0.0-alpha.3 116 | 117 | - edge case handling and more flexible configs (#406) 118 | 119 | ## v2.0.0-alpha.2 120 | 121 | - Try fix missing Chromium error 122 | 123 | ## v2.0.0-alpha.1 124 | 125 | - Update test harness to use ts-node and vite #405 126 | 127 | ## v1.0.0-alpha.8 128 | 129 | yarn 3 fixes 130 | 131 | - fix: Fix error codes returned by ocular-test, ocular-lint, etc (fork#7) 132 | - Fix error codes returned by ocular-test, ocular-lint, etc 133 | - Drop node 12 from test matrix 134 | - chore: Run bash scripts using Node (fork#6) 135 | - Fix package.json format (fork#5) 136 | - Remove browserslist update from bootstrap (fork#3) 137 | - ESLint and prettier upgrade (fork#2) 138 | 139 | ## v1.0.0-alpha.7 140 | 141 | - chore(dev-tools): dependencies (#374) 142 | 143 | ## v1.0.0-alpha.6 144 | 145 | - feat(dev-tools): Add typescript build support (#372) 146 | - chore: prettier fixes (#373) 147 | - babel targets: explicit support for async functions in ESM, reduces runtime dependencies. (#366) 148 | - chore(docs): Split docs per module (#371) 149 | - feat(dev-tools): Partial webpack 5 support (#370) 150 | - chore(dev-tools): update browser list on bootstrap (#367) 151 | - chore(dev-tools): improve typings (#369) 152 | - fix(dev-tools): Fix Node 16 build (#368) 153 | - fix(dev-tools): For ES Modules, look also for .ocularrc.cjs (#365) 154 | 155 | ## v1.0.0-alpha.5 156 | 157 | - feat(dev-tools): export getOcularConfig (#363) 158 | - chore: Add github CI (#364) 159 | 160 | ## v1.0.0-alpha.4 161 | 162 | - chore: Move deepmerge dep to dev-tools 163 | 164 | ## v1.0.0-alpha.3 165 | 166 | - feat(dev-tools): Add typescript support (#361) 167 | 168 | ## v1.0.0-alpha.3 169 | 170 | - feat(dev-tools): Add deepMerge export 171 | 172 | ## v1.0.0-alpha.1 173 | 174 | - feat: ocular-tsify using ts-smoosh (#357) 175 | - chore: Improve JSDoc (#354) 176 | - feat: log commands issued by ocular (#353) 177 | - feat: Add typescript exports for ocular functions, and test example (#352) 178 | 179 | ## v0.3.0 180 | 181 | - Change build targets (#349) 182 | 183 | ## v0.2.3 184 | 185 | - Fix coverage calculation (#348) 186 | 187 | ## v0.2.2 188 | 189 | - Support custom tag in publish script (#347) 190 | 191 | ## v0.2.1 192 | 193 | - Fix: extensions list from config wasn't used when executing ESLint (#345) 194 | 195 | ## v0.2.0 196 | 197 | - Support `extensions` setting for Babel in config 198 | 199 | ## v0.1.8 200 | 201 | - remove more jq usage 202 | 203 | ## v0.1.7 204 | 205 | - remove dependency on jq (#302) 206 | 207 | ## v0.1.6 208 | 209 | - dev-tools: Bump es6 build targets to Node 10 (#287) 210 | - Fix eslint error when using 'ocular-lint fix' (#286) 211 | 212 | ## v0.1.5 213 | 214 | - Fix bump script to detect peerDependencies (#284) 215 | 216 | ## v0.1.4 217 | 218 | - Fix building selected modules (#282) 219 | 220 | ## v0.1.1 221 | 222 | - Add `tape-promise` to dependencies 223 | 224 | ## v0.1.0 225 | 226 | - Ensure `test` folder is published 227 | 228 | ## v0.0.33 229 | 230 | - Fix bump script (#278) 231 | 232 | ## v0.0.32 233 | 234 | - ocular-build: babel now called with --copy-files (#276) 235 | 236 | ## v0.0.31 237 | 238 | - Update bump script to use full package name (#265) 239 | 240 | ## v0.0.30 241 | 242 | - test assertions (#248) 243 | - tweak build to accept options to build selected targets. (#251) 244 | - Improve pre-commit lint script (#258) 245 | - Fix warnings in switch case (#259) 246 | 247 | ## v0.0.29 248 | 249 | - Fix targets 250 | 251 | ## v0.0.28 252 | 253 | - Stricter es6 targets to avoid transforming async/await (#240) 254 | 255 | ## v0.0.27 256 | 257 | - Report coverage using src (#209) 258 | 259 | ## v0.0.26 260 | 261 | - Update publish script for unirepo (#201) 262 | 263 | ## v0.0.25 264 | 265 | - Bump webpack-bundle-analyzer version (#192) 266 | - Update Lerna version (#197) 267 | 268 | ## v0.0.24 269 | 270 | - Only install one copy of chromium (#176) 271 | 272 | ## v0.0.23 273 | 274 | - fix module aliasing for probe.gl (#158) 275 | 276 | ## v0.0.22 277 | 278 | - Expose BrowserTestRunner configurations (#155) 279 | 280 | ## v0.0.21 281 | 282 | - Remove hard reference of reify (#154) 283 | 284 | ## v0.0.20 285 | 286 | - Fix build error when package.json is missing (#152) 287 | 288 | ## v0.0.19 289 | 290 | - Upgrade to probe.gl@3.0.0 291 | 292 | ## v0.0.18 293 | 294 | - Fix lint script (prettier error check) 295 | 296 | ## v0.0.17 297 | 298 | - Monorepo publish now force publishes all packages, and uses exact dependencies 299 | 300 | ## v0.0.16 301 | 302 | - Update lint script (#121) 303 | - update publish script for unirepo (#122) 304 | 305 | ## v0.0.15 306 | 307 | - Fix script shebangs (#120) 308 | 309 | ## v0.0.14 310 | 311 | - Add auto aliases to module/test (#117) 312 | 313 | ## v0.0.13 314 | 315 | - remove babel config override logic (#116) 316 | - allow configs to be used outside of package root (#115) 317 | 318 | ## v0.0.12 319 | 320 | - Fix bootstrap script 321 | 322 | ## v0.0.11 323 | 324 | - Run coverage on ci (#112) 325 | - Support babel/webpack config files in package (#113) 326 | - Update documentation (#114) 327 | 328 | ## v0.0.10 329 | 330 | - Move reify to peerDependency 331 | 332 | ## v0.0.8 333 | 334 | - Fix publish script (#106) 335 | - use prettier on markdowns (#102) 336 | - add config system (#104) 337 | - Add test harness (#105) 338 | - Fix metrics collection (#107) 339 | - Add user config for lint (#108) 340 | - Fix coverage script (#111) 341 | 342 | ## v0.0.7 343 | 344 | - Fix build script in Linux (#87) 345 | - Remove puppeteer dependency (#88) 346 | 347 | ## v0.0.6 348 | 349 | - Support monorepo in build & clean scripts (#86) 350 | - Expose bootstrap script; consolidate monorepo scripts (#85) 351 | 352 | ## v0.0.5 353 | 354 | - Remove transform-builtin-extend from common babel.config.js 355 | --------------------------------------------------------------------------------