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,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;
}