larry babby and threejs for glsl

This commit is contained in:
Sam
2024-06-24 21:24:00 +12:00
parent 87d5dc634d
commit 907ebae4c0
6474 changed files with 1279596 additions and 8 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-present Devon Govett
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,105 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _plugin() {
const data = require("@parcel/plugin");
_plugin = function () {
return data;
};
return data;
}
function _nullthrows() {
const data = _interopRequireDefault(require("nullthrows"));
_nullthrows = function () {
return data;
};
return data;
}
function _semver() {
const data = _interopRequireDefault(require("semver"));
_semver = function () {
return data;
};
return data;
}
function _posthtmlParser() {
const data = require("posthtml-parser");
_posthtmlParser = function () {
return data;
};
return data;
}
function _posthtmlRender() {
const data = require("posthtml-render");
_posthtmlRender = function () {
return data;
};
return data;
}
var _dependencies = _interopRequireDefault(require("./dependencies"));
var _inline = _interopRequireDefault(require("./inline"));
function _diagnostic() {
const data = _interopRequireDefault(require("@parcel/diagnostic"));
_diagnostic = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _default = exports.default = new (_plugin().Transformer)({
canReuseAST({
ast
}) {
return ast.type === 'posthtml' && _semver().default.satisfies(ast.version, '^0.4.0');
},
async parse({
asset
}) {
return {
type: 'posthtml',
version: '0.4.1',
program: (0, _posthtmlParser().parser)(await asset.getCode(), {
directives: [{
name: /^\?/,
start: '<',
end: '>'
}],
sourceLocations: true,
xmlMode: true
})
};
},
async transform({
asset
}) {
asset.bundleBehavior = 'isolated';
const ast = (0, _nullthrows().default)(await asset.getAST());
try {
(0, _dependencies.default)(asset, ast);
} catch (errors) {
throw new (_diagnostic().default)({
diagnostic: errors.map(error => ({
message: error.message,
origin: '@parcel/transformer-svg',
codeFrames: [{
filePath: error.filePath,
language: 'svg',
codeHighlights: [error.loc]
}]
}))
});
}
const inlineAssets = (0, _inline.default)(asset, ast);
return [asset, ...inlineAssets];
},
generate({
ast
}) {
return {
content: (0, _posthtmlRender().render)(ast.program)
};
}
});

View File

@@ -0,0 +1,135 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = collectDependencies;
exports.parseFuncIRI = parseFuncIRI;
function _posthtml() {
const data = _interopRequireDefault(require("posthtml"));
_posthtml = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// A list of all attributes that may produce a dependency
// Based on https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute
// See also https://www.w3.org/TR/SVG/attindex.html and https://www.w3.org/TR/SVG11/attindex.html
// SVG animation elements are excluded because they may only reference elements in the same document: https://www.w3.org/TR/SVG/linking.html#processingURL-fetch
const HREF_ATTRS = ['a', 'use', 'feImage', 'image', 'linearGradient', 'radialGradient', 'pattern', 'mpath', 'textPath', 'script'];
const ATTRS = {
href: HREF_ATTRS,
'xlink:href': [...HREF_ATTRS, 'altGlyph', 'cursor', 'filter', 'font-face-uri', 'glyphRef', 'tref', 'color-profile']
};
// Attributes that allow url() to reference another element, either in the same document or a different one.
// https://www.w3.org/TR/SVG11/linking.html#processingIRI
const FUNC_IRI_ATTRS = new Set(['fill', 'stroke', 'clip-path', 'color-profile', 'cursor', 'filter', 'marker', 'marker-start', 'marker-mid', 'marker-end', 'mask',
// SVG2 - https://www.w3.org/TR/SVG/linking.html#processingURL-validity
'shape-inside', 'shape-subtract', 'mask-image']);
// https://www.w3.org/TR/css3-values/#urls
const FUNC_IRI_RE = /^url\((?:((['"])(.*?)\2(\s+.*)?)|((?:\\[\s'"]|[^\s'"])+))\)$/;
const ESCAPE_RE = /\\(.|\n|\r|\u2028|\u2029)/;
function parseFuncIRI(value) {
let m = value.match(FUNC_IRI_RE);
if (m) {
var _m$;
let url = (m[3] || m[5]).replace(ESCAPE_RE, '$1');
let modifier = (_m$ = m[4]) !== null && _m$ !== void 0 ? _m$ : '';
return [url, modifier];
}
}
// Options to be passed to `addDependency` for certain tags + attributes
const OPTIONS = {
a: {
href: {
needsStableName: true
},
'xlink:href': {
needsStableName: true
}
}
};
function collectDependencies(asset, ast) {
let isDirty = false;
const errors = [];
(0, _posthtml().default)().walk.call(ast.program, node => {
// Ideally we'd have location information for specific attributes...
let getLoc = () => node.location ? {
filePath: asset.filePath,
start: node.location.start,
end: node.location.end
} : undefined;
if (typeof node === 'string' && node.startsWith('<?xml-stylesheet')) {
return node.replace(/(?<=(?:^|\s)href\s*=\s*")(.+?)(?=")/i, href => {
isDirty = true;
return asset.addURLDependency(href, {
priority: 'parallel'
});
});
}
const {
tag,
attrs
} = node;
if (!attrs) {
return node;
}
for (const attr in attrs) {
// Check for id references
if (attrs[attr][0] === '#') {
continue;
}
const elements = ATTRS[attr];
if (elements && elements.includes(node.tag)) {
var _OPTIONS$tag;
// Check for empty string
if (attrs[attr].length === 0) {
errors.push({
message: `'${attr}' should not be empty string`,
filePath: asset.filePath,
loc: node.location
});
}
let options = (_OPTIONS$tag = OPTIONS[tag]) === null || _OPTIONS$tag === void 0 ? void 0 : _OPTIONS$tag[attr];
if (node.tag === 'script') {
options = {
priority: 'parallel',
env: {
sourceType: attrs.type === 'module' ? 'module' : 'script',
// SVG script elements do not support type="module" natively yet.
outputFormat: 'global',
loc: getLoc()
}
};
delete attrs.type;
}
attrs[attr] = asset.addURLDependency(attrs[attr], {
...options,
loc: getLoc()
});
isDirty = true;
}
if (FUNC_IRI_ATTRS.has(attr)) {
let parsed = parseFuncIRI(attrs[attr]);
if (parsed) {
let depId = asset.addURLDependency(parsed[0], {
loc: getLoc()
});
attrs[attr] = `url('${depId}'${parsed[1]})`;
isDirty = true;
}
}
}
return node;
});
if (errors.length > 0) {
throw errors;
}
if (isDirty) {
asset.setAST(ast);
}
}

View File

@@ -0,0 +1,135 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractInlineAssets;
function _rust() {
const data = require("@parcel/rust");
_rust = function () {
return data;
};
return data;
}
function _posthtml() {
const data = _interopRequireDefault(require("posthtml"));
_posthtml = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const SCRIPT_TYPES = {
'application/ecmascript': 'js',
'application/javascript': 'js',
'text/javascript': 'js',
module: 'js'
};
function extractInlineAssets(asset, ast) {
const program = ast.program;
let key = 0;
// Extract <style> elements for processing.
const parts = [];
(0, _posthtml().default)().walk.call(program, node => {
if (node.tag === 'style' || node.tag === 'script') {
var _node$location;
const value = node.content && node.content.join('');
if (!value) {
return node;
}
let type, env;
if (node.tag === 'style') {
if (node.attrs && node.attrs.type != null) {
type = node.attrs.type.split('/')[1];
} else {
type = 'css';
}
} else if (node.tag === 'script') {
if (node.attrs && SCRIPT_TYPES[node.attrs.type]) {
type = SCRIPT_TYPES[node.attrs.type];
} else if (node.attrs) {
type = node.attrs.type.split('/')[1];
} else {
type = 'js';
}
env = {
sourceType: node.attrs && node.attrs.type === 'module' ? 'module' : 'script',
// SVG script elements do not support type="module" natively yet.
outputFormat: 'global',
loc: node.location ? {
filePath: asset.filePath,
start: node.location.start,
end: node.location.end
} : undefined
};
}
if (!type) {
return node;
}
let attrs = node.attrs;
if (!attrs) {
attrs = {};
node.attrs = attrs;
}
// Inform packager to remove type, since CSS and JS are the defaults.
delete attrs.type;
let parcelKey;
// allow a script/style tag to declare its key
if (attrs['data-parcel-key']) {
parcelKey = attrs['data-parcel-key'];
} else {
parcelKey = (0, _rust().hashString)(`${asset.id}:${key++}`);
}
// insert parcelId to allow us to retrieve node during packaging
attrs['data-parcel-key'] = parcelKey;
asset.setAST(ast); // mark dirty
asset.addDependency({
specifier: parcelKey,
specifierType: 'esm'
});
parts.push({
type,
content: value,
uniqueKey: parcelKey,
bundleBehavior: 'inline',
env,
meta: {
type: 'tag',
// $FlowFixMe
node,
startLine: (_node$location = node.location) === null || _node$location === void 0 ? void 0 : _node$location.start.line
}
});
}
// Process inline style attributes.
let attrs = node.attrs;
let style = attrs === null || attrs === void 0 ? void 0 : attrs.style;
if (attrs != null && style != null) {
let parcelKey = (0, _rust().hashString)(`${asset.id}:${key++}`);
attrs.style = asset.addDependency({
specifier: parcelKey,
specifierType: 'esm'
});
asset.setAST(ast); // mark dirty
parts.push({
type: 'css',
content: style,
uniqueKey: parcelKey,
bundleBehavior: 'inline',
meta: {
type: 'attr',
// $FlowFixMe
node
}
});
}
return node;
});
return parts;
}

View File

@@ -0,0 +1,33 @@
{
"name": "@parcel/transformer-svg",
"version": "2.12.0",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"repository": {
"type": "git",
"url": "https://github.com/parcel-bundler/parcel.git"
},
"main": "lib/SVGTransformer.js",
"source": "src/SVGTransformer.js",
"engines": {
"node": ">= 12.0.0",
"parcel": "^2.12.0"
},
"dependencies": {
"@parcel/diagnostic": "2.12.0",
"@parcel/plugin": "2.12.0",
"@parcel/rust": "2.12.0",
"nullthrows": "^1.1.1",
"posthtml": "^0.16.5",
"posthtml-parser": "^0.10.1",
"posthtml-render": "^3.0.0",
"semver": "^7.5.2"
},
"gitHead": "2059029ee91e5f03a273b0954d3e629d7375f986"
}

View File

@@ -0,0 +1,68 @@
// @flow
import {Transformer} from '@parcel/plugin';
import nullthrows from 'nullthrows';
import semver from 'semver';
import {parser as parse} from 'posthtml-parser';
import {render} from 'posthtml-render';
import collectDependencies from './dependencies';
import extractInlineAssets from './inline';
import ThrowableDiagnostic from '@parcel/diagnostic';
export default (new Transformer({
canReuseAST({ast}) {
return ast.type === 'posthtml' && semver.satisfies(ast.version, '^0.4.0');
},
async parse({asset}) {
return {
type: 'posthtml',
version: '0.4.1',
program: parse(await asset.getCode(), {
directives: [
{
name: /^\?/,
start: '<',
end: '>',
},
],
sourceLocations: true,
xmlMode: true,
}),
};
},
async transform({asset}) {
asset.bundleBehavior = 'isolated';
const ast = nullthrows(await asset.getAST());
try {
collectDependencies(asset, ast);
} catch (errors) {
throw new ThrowableDiagnostic({
diagnostic: errors.map(error => ({
message: error.message,
origin: '@parcel/transformer-svg',
codeFrames: [
{
filePath: error.filePath,
language: 'svg',
codeHighlights: [error.loc],
},
],
})),
});
}
const inlineAssets = extractInlineAssets(asset, ast);
return [asset, ...inlineAssets];
},
generate({ast}) {
return {
content: render(ast.program),
};
},
}): Transformer);

View File

@@ -0,0 +1,163 @@
// @flow
import type {AST, MutableAsset} from '@parcel/types';
import PostHTML from 'posthtml';
// A list of all attributes that may produce a dependency
// Based on https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute
// See also https://www.w3.org/TR/SVG/attindex.html and https://www.w3.org/TR/SVG11/attindex.html
// SVG animation elements are excluded because they may only reference elements in the same document: https://www.w3.org/TR/SVG/linking.html#processingURL-fetch
const HREF_ATTRS = [
'a',
'use',
'feImage',
'image',
'linearGradient',
'radialGradient',
'pattern',
'mpath',
'textPath',
'script',
];
const ATTRS = {
href: HREF_ATTRS,
'xlink:href': [
...HREF_ATTRS,
'altGlyph',
'cursor',
'filter',
'font-face-uri',
'glyphRef',
'tref',
'color-profile',
],
};
// Attributes that allow url() to reference another element, either in the same document or a different one.
// https://www.w3.org/TR/SVG11/linking.html#processingIRI
const FUNC_IRI_ATTRS = new Set([
'fill',
'stroke',
'clip-path',
'color-profile',
'cursor',
'filter',
'marker',
'marker-start',
'marker-mid',
'marker-end',
'mask',
// SVG2 - https://www.w3.org/TR/SVG/linking.html#processingURL-validity
'shape-inside',
'shape-subtract',
'mask-image',
]);
// https://www.w3.org/TR/css3-values/#urls
const FUNC_IRI_RE =
/^url\((?:((['"])(.*?)\2(\s+.*)?)|((?:\\[\s'"]|[^\s'"])+))\)$/;
const ESCAPE_RE = /\\(.|\n|\r|\u2028|\u2029)/;
export function parseFuncIRI(value: string): ?[string, string] {
let m = value.match(FUNC_IRI_RE);
if (m) {
let url = (m[3] || m[5]).replace(ESCAPE_RE, '$1');
let modifier = m[4] ?? '';
return [url, modifier];
}
}
// Options to be passed to `addDependency` for certain tags + attributes
const OPTIONS = {
a: {
href: {needsStableName: true},
'xlink:href': {needsStableName: true},
},
};
export default function collectDependencies(asset: MutableAsset, ast: AST) {
let isDirty = false;
const errors = [];
PostHTML().walk.call(ast.program, node => {
// Ideally we'd have location information for specific attributes...
let getLoc = () =>
node.location
? {
filePath: asset.filePath,
start: node.location.start,
end: node.location.end,
}
: undefined;
if (typeof node === 'string' && node.startsWith('<?xml-stylesheet')) {
return node.replace(/(?<=(?:^|\s)href\s*=\s*")(.+?)(?=")/i, href => {
isDirty = true;
return asset.addURLDependency(href, {priority: 'parallel'});
});
}
const {tag, attrs} = node;
if (!attrs) {
return node;
}
for (const attr in attrs) {
// Check for id references
if (attrs[attr][0] === '#') {
continue;
}
const elements = ATTRS[attr];
if (elements && elements.includes(node.tag)) {
// Check for empty string
if (attrs[attr].length === 0) {
errors.push({
message: `'${attr}' should not be empty string`,
filePath: asset.filePath,
loc: node.location,
});
}
let options = OPTIONS[tag]?.[attr];
if (node.tag === 'script') {
options = {
priority: 'parallel',
env: {
sourceType: attrs.type === 'module' ? 'module' : 'script',
// SVG script elements do not support type="module" natively yet.
outputFormat: 'global',
loc: getLoc(),
},
};
delete attrs.type;
}
attrs[attr] = asset.addURLDependency(attrs[attr], {
...options,
loc: getLoc(),
});
isDirty = true;
}
if (FUNC_IRI_ATTRS.has(attr)) {
let parsed = parseFuncIRI(attrs[attr]);
if (parsed) {
let depId = asset.addURLDependency(parsed[0], {
loc: getLoc(),
});
attrs[attr] = `url('${depId}'${parsed[1]})`;
isDirty = true;
}
}
}
return node;
});
if (errors.length > 0) {
throw errors;
}
if (isDirty) {
asset.setAST(ast);
}
}

View File

@@ -0,0 +1,136 @@
// @flow
import type {AST, MutableAsset, TransformerResult} from '@parcel/types';
import {hashString} from '@parcel/rust';
import type {PostHTMLNode} from 'posthtml';
import PostHTML from 'posthtml';
const SCRIPT_TYPES = {
'application/ecmascript': 'js',
'application/javascript': 'js',
'text/javascript': 'js',
module: 'js',
};
export default function extractInlineAssets(
asset: MutableAsset,
ast: AST,
): Array<TransformerResult> {
const program: PostHTMLNode = ast.program;
let key = 0;
// Extract <style> elements for processing.
const parts: Array<TransformerResult> = [];
PostHTML().walk.call(program, (node: PostHTMLNode) => {
if (node.tag === 'style' || node.tag === 'script') {
const value = node.content && node.content.join('');
if (!value) {
return node;
}
let type, env;
if (node.tag === 'style') {
if (node.attrs && node.attrs.type != null) {
type = node.attrs.type.split('/')[1];
} else {
type = 'css';
}
} else if (node.tag === 'script') {
if (node.attrs && SCRIPT_TYPES[node.attrs.type]) {
type = SCRIPT_TYPES[node.attrs.type];
} else if (node.attrs) {
type = node.attrs.type.split('/')[1];
} else {
type = 'js';
}
env = {
sourceType:
node.attrs && node.attrs.type === 'module' ? 'module' : 'script',
// SVG script elements do not support type="module" natively yet.
outputFormat: 'global',
loc: node.location
? {
filePath: asset.filePath,
start: node.location.start,
end: node.location.end,
}
: undefined,
};
}
if (!type) {
return node;
}
let attrs = node.attrs;
if (!attrs) {
attrs = {};
node.attrs = attrs;
}
// Inform packager to remove type, since CSS and JS are the defaults.
delete attrs.type;
let parcelKey;
// allow a script/style tag to declare its key
if (attrs['data-parcel-key']) {
parcelKey = attrs['data-parcel-key'];
} else {
parcelKey = hashString(`${asset.id}:${key++}`);
}
// insert parcelId to allow us to retrieve node during packaging
attrs['data-parcel-key'] = parcelKey;
asset.setAST(ast); // mark dirty
asset.addDependency({
specifier: parcelKey,
specifierType: 'esm',
});
parts.push({
type,
content: value,
uniqueKey: parcelKey,
bundleBehavior: 'inline',
env,
meta: {
type: 'tag',
// $FlowFixMe
node,
startLine: node.location?.start.line,
},
});
}
// Process inline style attributes.
let attrs = node.attrs;
let style = attrs?.style;
if (attrs != null && style != null) {
let parcelKey = hashString(`${asset.id}:${key++}`);
attrs.style = asset.addDependency({
specifier: parcelKey,
specifierType: 'esm',
});
asset.setAST(ast); // mark dirty
parts.push({
type: 'css',
content: style,
uniqueKey: parcelKey,
bundleBehavior: 'inline',
meta: {
type: 'attr',
// $FlowFixMe
node,
},
});
}
return node;
});
return parts;
}

View File

@@ -0,0 +1,24 @@
import {parseFuncIRI} from '../src/dependencies';
import assert from 'assert';
describe('parseFuncIRI', () => {
it('should parse unquoted url()', () => {
assert.deepEqual(parseFuncIRI('url(test)'), ['test', '']);
assert.deepEqual(parseFuncIRI('url(test hi)'), null);
assert.deepEqual(parseFuncIRI('url(test"hi)'), null);
assert.deepEqual(parseFuncIRI('url(test\\ hi)'), ['test hi', '']);
assert.deepEqual(parseFuncIRI('url(test\\"hi)'), ['test"hi', '']);
assert.deepEqual(parseFuncIRI('url(test\nhi)'), null);
assert.deepEqual(parseFuncIRI('url(test\\\nhi)'), ['test\nhi', '']);
});
it('should parse quoted url()', () => {
assert.deepEqual(parseFuncIRI('url("test")'), ['test', '']);
assert.deepEqual(parseFuncIRI("url('test')"), ['test', '']);
assert.deepEqual(parseFuncIRI('url(\'test")'), null);
assert.deepEqual(parseFuncIRI('url("test\')'), null);
assert.deepEqual(parseFuncIRI('url("test)'), null);
assert.deepEqual(parseFuncIRI('url("test" hi)'), ['test', ' hi']);
assert.deepEqual(parseFuncIRI('url("te\\"st" hi)'), ['te"st', ' hi']);
});
});