mirror of https://github.com/sveltejs/svelte
parent
25488772e2
commit
a4f7624b9a
@ -1 +0,0 @@
|
|||||||
test/test.js
|
|
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-console": "off"
|
"no-console": "off",
|
||||||
|
"@typescript-eslint/no-var-requires": "off",
|
||||||
|
"@typescript-eslint/no-namespace": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
import jsdom from 'jsdom';
|
||||||
|
export {};
|
||||||
|
declare global {
|
||||||
|
namespace NodeJS {
|
||||||
|
interface Global {
|
||||||
|
document: Document;
|
||||||
|
window: jsdom.DOMWindow;
|
||||||
|
navigator: Navigator;
|
||||||
|
getComputedStyle: jsdom.DOMWindow['getComputedStyle'];
|
||||||
|
requestAnimationFrame: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
// this file will replace all the expected.js files with their _actual
|
|
||||||
// equivalents. Only use it when you're sure that you haven't
|
|
||||||
// broken anything!
|
|
||||||
const fs = require("fs");
|
|
||||||
const glob = require("tiny-glob/sync.js");
|
|
||||||
|
|
||||||
glob("samples/*/_actual.js", { cwd: __dirname }).forEach(file => {
|
|
||||||
const actual = fs.readFileSync(`${__dirname}/${file}`, "utf-8");
|
|
||||||
fs.writeFileSync(
|
|
||||||
`${__dirname}/${file.replace("_actual.js", "expected.js")}`,
|
|
||||||
actual
|
|
||||||
);
|
|
||||||
});
|
|
@ -0,0 +1,39 @@
|
|||||||
|
import { readFileSync, writeFileSync } from 'fs';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
// this file will replace all the expected.js files with their _actual
|
||||||
|
// equivalents. Only use it when you're sure that you haven't
|
||||||
|
// broken anything!
|
||||||
|
const svelte = (function loadSvelte(test) {
|
||||||
|
process.env.TEST = test ? 'true' : '';
|
||||||
|
const resolved = require.resolve('../../compiler.js');
|
||||||
|
delete require.cache[resolved];
|
||||||
|
return require(resolved);
|
||||||
|
})(false);
|
||||||
|
function loadConfig(file) {
|
||||||
|
try {
|
||||||
|
const resolved = require.resolve(file);
|
||||||
|
delete require.cache[resolved];
|
||||||
|
|
||||||
|
const config = require(resolved);
|
||||||
|
return config.default || config;
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code === 'MODULE_NOT_FOUND') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require(resolve(__dirname, '../tiny-glob.ts'))
|
||||||
|
.glob('samples/*/_actual.js', { cwd: __dirname })
|
||||||
|
.forEach((file) => {
|
||||||
|
writeFileSync(
|
||||||
|
`${__dirname}/${file.replace('_actual.js', 'expected.js')}`,
|
||||||
|
svelte
|
||||||
|
.compile(
|
||||||
|
readFileSync(`${__dirname}/${file.replace('_actual.js', 'input.svelte')}`, 'utf-8').replace(/\s+$/, ''),
|
||||||
|
loadConfig(`${__dirname}/${file.replace('_actual.js', '_config.js')}`).options
|
||||||
|
)
|
||||||
|
.js.code.replace(/generated by Svelte v\d+\.\d+\.\d+(-\w+\.\d+)?/, 'generated by Svelte vX.Y.Z')
|
||||||
|
);
|
||||||
|
});
|
@ -1,4 +1,4 @@
|
|||||||
import * as assert from 'assert';
|
import { assert } from '../test';
|
||||||
import { get } from '../../store';
|
import { get } from '../../store';
|
||||||
import { spring, tweened } from '../../motion';
|
import { spring, tweened } from '../../motion';
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
// this file will replace all the output.json files with their _actual.json
|
|
||||||
// equivalents. Only use it when you're sure that you haven't
|
|
||||||
// broken anything!
|
|
||||||
const fs = require("fs");
|
|
||||||
const glob = require("tiny-glob/sync.js");
|
|
||||||
|
|
||||||
glob("samples/*/_actual.json", { cwd: __dirname }).forEach(file => {
|
|
||||||
const actual = fs.readFileSync(`${__dirname}/${file}`, "utf-8");
|
|
||||||
fs.writeFileSync(
|
|
||||||
`${__dirname}/${file.replace("_actual.json", "output.json")}`,
|
|
||||||
actual
|
|
||||||
);
|
|
||||||
});
|
|
@ -0,0 +1,31 @@
|
|||||||
|
import { readFileSync, writeFileSync } from 'fs';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
// this file will replace all the expected.js files with their _actual
|
||||||
|
// equivalents. Only use it when you're sure that you haven't
|
||||||
|
// broken anything!
|
||||||
|
const svelte = (function loadSvelte(test) {
|
||||||
|
process.env.TEST = test ? 'true' : '';
|
||||||
|
const resolved = require.resolve('../../compiler.js');
|
||||||
|
delete require.cache[resolved];
|
||||||
|
return require(resolved);
|
||||||
|
})(false);
|
||||||
|
require(resolve(__dirname, '../tiny-glob.ts'))
|
||||||
|
.glob('samples/*/input.svelte', { cwd: __dirname })
|
||||||
|
.forEach((file) => {
|
||||||
|
try {
|
||||||
|
writeFileSync(
|
||||||
|
`${__dirname}/${file.replace('input.svelte', 'output.json')}`,
|
||||||
|
JSON.stringify(
|
||||||
|
svelte.compile(readFileSync(`${__dirname}/${file}`, 'utf-8').replace(/\s+$/, ''), { generate: false }).ast,
|
||||||
|
null,
|
||||||
|
'\t'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name !== 'ParseError') throw e;
|
||||||
|
writeFileSync(
|
||||||
|
`${__dirname}/${file.replace('input.svelte', 'error.json')}`,
|
||||||
|
JSON.stringify({ ...e, message: e.message }, null, '\t')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
@ -1,9 +1,9 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as assert from 'assert';
|
import { loadConfig, svelte } from '../helpers';
|
||||||
import { loadConfig, svelte } from '../helpers.js';
|
import { assert } from '../test';
|
||||||
|
|
||||||
describe('preprocess', () => {
|
describe('preprocess', () => {
|
||||||
fs.readdirSync(`${__dirname}/samples`).forEach(dir => {
|
fs.readdirSync(`${__dirname}/samples`).forEach((dir) => {
|
||||||
if (dir[0] === '.') return;
|
if (dir[0] === '.') return;
|
||||||
|
|
||||||
const config = loadConfig(`${__dirname}/samples/${dir}/_config.js`);
|
const config = loadConfig(`${__dirname}/samples/${dir}/_config.js`);
|
@ -1,38 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
require('source-map-support').install();
|
|
||||||
|
|
||||||
process.env.TEST = true;
|
|
||||||
|
|
||||||
require.extensions['.js'] = function(module, filename) {
|
|
||||||
const exports = [];
|
|
||||||
|
|
||||||
let code = fs.readFileSync(filename, 'utf-8')
|
|
||||||
.replace(/^import \* as (\w+) from ['"]([^'"]+)['"];?/gm, 'var $1 = require("$2");')
|
|
||||||
.replace(/^import (\w+) from ['"]([^'"]+)['"];?/gm, 'var {default: $1} = require("$2");')
|
|
||||||
.replace(/^import {([^}]+)} from ['"](.+)['"];?/gm, 'var {$1} = require("$2");')
|
|
||||||
.replace(/^export default /gm, 'exports.default = ')
|
|
||||||
.replace(/^export (const|let|var|class|function) (\w+)/gm, (match, type, name) => {
|
|
||||||
exports.push(name);
|
|
||||||
return `${type} ${name}`;
|
|
||||||
})
|
|
||||||
.replace(/^export \{([^}]+)\}(?: from ['"]([^'"]+)['"];?)?/gm, (match, names, source) => {
|
|
||||||
names.split(',').filter(Boolean).forEach(name => {
|
|
||||||
exports.push(name);
|
|
||||||
});
|
|
||||||
|
|
||||||
return source ? `const { ${names} } = require("${source}");` : '';
|
|
||||||
})
|
|
||||||
.replace(/^export function (\w+)/gm, 'exports.$1 = function $1');
|
|
||||||
|
|
||||||
exports.forEach(name => {
|
|
||||||
code += `\nexports.${name} = ${name};`;
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
return module._compile(code, filename);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(code); // eslint-disable-line no-console
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,73 +0,0 @@
|
|||||||
import * as fs from "fs";
|
|
||||||
import * as path from "path";
|
|
||||||
import * as assert from "assert";
|
|
||||||
import { svelte } from "../helpers.js";
|
|
||||||
import { SourceMapConsumer } from "source-map";
|
|
||||||
import { getLocator } from "locate-character";
|
|
||||||
|
|
||||||
describe("sourcemaps", () => {
|
|
||||||
fs.readdirSync(`${__dirname}/samples`).forEach(dir => {
|
|
||||||
if (dir[0] === ".") return;
|
|
||||||
|
|
||||||
// add .solo to a sample directory name to only run that test
|
|
||||||
const solo = /\.solo/.test(dir);
|
|
||||||
const skip = /\.skip/.test(dir);
|
|
||||||
|
|
||||||
if (solo && process.env.CI) {
|
|
||||||
throw new Error("Forgot to remove `solo: true` from test");
|
|
||||||
}
|
|
||||||
|
|
||||||
(solo ? it.only : skip ? it.skip : it)(dir, async () => {
|
|
||||||
const filename = path.resolve(
|
|
||||||
`${__dirname}/samples/${dir}/input.svelte`
|
|
||||||
);
|
|
||||||
const outputFilename = path.resolve(
|
|
||||||
`${__dirname}/samples/${dir}/output`
|
|
||||||
);
|
|
||||||
|
|
||||||
const input = fs.readFileSync(filename, "utf-8").replace(/\s+$/, "");
|
|
||||||
const { js, css } = svelte.compile(input, {
|
|
||||||
filename,
|
|
||||||
outputFilename: `${outputFilename}.js`,
|
|
||||||
cssOutputFilename: `${outputFilename}.css`
|
|
||||||
});
|
|
||||||
|
|
||||||
const _code = js.code.replace(/Svelte v\d+\.\d+\.\d+/, match => match.replace(/\d/g, 'x'));
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
`${outputFilename}.js`,
|
|
||||||
`${_code}\n//# sourceMappingURL=output.js.map`
|
|
||||||
);
|
|
||||||
fs.writeFileSync(
|
|
||||||
`${outputFilename}.js.map`,
|
|
||||||
JSON.stringify(js.map, null, " ")
|
|
||||||
);
|
|
||||||
|
|
||||||
if (css.code) {
|
|
||||||
fs.writeFileSync(
|
|
||||||
`${outputFilename}.css`,
|
|
||||||
`${css.code}\n/*# sourceMappingURL=output.css.map */`
|
|
||||||
);
|
|
||||||
fs.writeFileSync(
|
|
||||||
`${outputFilename}.css.map`,
|
|
||||||
JSON.stringify(css.map, null, " ")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.deepEqual(js.map.sources, ["input.svelte"]);
|
|
||||||
if (css.map) assert.deepEqual(css.map.sources, ["input.svelte"]);
|
|
||||||
|
|
||||||
const { test } = require(`./samples/${dir}/test.js`);
|
|
||||||
|
|
||||||
const locateInSource = getLocator(input);
|
|
||||||
|
|
||||||
const smc = await new SourceMapConsumer(js.map);
|
|
||||||
const locateInGenerated = getLocator(_code);
|
|
||||||
|
|
||||||
const smcCss = css.map && await new SourceMapConsumer(css.map);
|
|
||||||
const locateInGeneratedCss = getLocator(css.code || '');
|
|
||||||
|
|
||||||
test({ assert, code: _code, map: js.map, smc, smcCss, locateInSource, locateInGenerated, locateInGeneratedCss });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -0,0 +1,57 @@
|
|||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import { svelte } from '../helpers';
|
||||||
|
import { SourceMapConsumer } from 'source-map';
|
||||||
|
import { getLocator } from 'locate-character';
|
||||||
|
|
||||||
|
describe('sourcemaps', () => {
|
||||||
|
fs.readdirSync(`${__dirname}/samples`).forEach((dir) => {
|
||||||
|
if (dir[0] === '.') return;
|
||||||
|
|
||||||
|
// add .solo to a sample directory name to only run that test
|
||||||
|
const solo = /\.solo/.test(dir);
|
||||||
|
const skip = /\.skip/.test(dir);
|
||||||
|
|
||||||
|
if (solo && process.env.CI) {
|
||||||
|
throw new Error('Forgot to remove `solo: true` from test');
|
||||||
|
}
|
||||||
|
|
||||||
|
(solo ? it.only : skip ? it.skip : it)(dir, async () => {
|
||||||
|
const filename = path.resolve(`${__dirname}/samples/${dir}/input.svelte`);
|
||||||
|
const outputFilename = path.resolve(`${__dirname}/samples/${dir}/output`);
|
||||||
|
|
||||||
|
const input = fs.readFileSync(filename, 'utf-8').replace(/\s+$/, '');
|
||||||
|
const { js, css } = svelte.compile(input, {
|
||||||
|
filename,
|
||||||
|
outputFilename: `${outputFilename}.js`,
|
||||||
|
cssOutputFilename: `${outputFilename}.css`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const _code = js.code.replace(/Svelte v\d+\.\d+\.\d+/, (match) => match.replace(/\d/g, 'x'));
|
||||||
|
|
||||||
|
fs.writeFileSync(`${outputFilename}.js`, `${_code}\n//# sourceMappingURL=output.js.map`);
|
||||||
|
fs.writeFileSync(`${outputFilename}.js.map`, JSON.stringify(js.map, null, ' '));
|
||||||
|
|
||||||
|
if (css.code) {
|
||||||
|
fs.writeFileSync(`${outputFilename}.css`, `${css.code}\n/*# sourceMappingURL=output.css.map */`);
|
||||||
|
fs.writeFileSync(`${outputFilename}.css.map`, JSON.stringify(css.map, null, ' '));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.deepEqual(js.map.sources, ['input.svelte']);
|
||||||
|
if (css.map) assert.deepEqual(css.map.sources, ['input.svelte']);
|
||||||
|
|
||||||
|
const { test } = require(`./samples/${dir}/test.js`);
|
||||||
|
|
||||||
|
const locateInSource = getLocator(input);
|
||||||
|
|
||||||
|
const smc = await new SourceMapConsumer(js.map);
|
||||||
|
const locateInGenerated = getLocator(_code);
|
||||||
|
|
||||||
|
const smcCss = css.map && (await new SourceMapConsumer(css.map));
|
||||||
|
const locateInGeneratedCss = getLocator(css.code || '');
|
||||||
|
|
||||||
|
test({ assert, code: _code, map: js.map, smc, smcCss, locateInSource, locateInGenerated, locateInGeneratedCss });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,21 +0,0 @@
|
|||||||
const glob = require('tiny-glob/sync.js');
|
|
||||||
|
|
||||||
require('./setup');
|
|
||||||
|
|
||||||
// bind internal to jsdom
|
|
||||||
require('./helpers');
|
|
||||||
require('../internal');
|
|
||||||
|
|
||||||
console.clear();
|
|
||||||
|
|
||||||
const test_folders = glob('*/index.js', { cwd: 'test' });
|
|
||||||
const solo_folders = test_folders.filter(folder => /\.solo/.test(folder));
|
|
||||||
|
|
||||||
if (solo_folders.length) {
|
|
||||||
if (process.env.CI) {
|
|
||||||
throw new Error('Forgot to remove `.solo` from test');
|
|
||||||
}
|
|
||||||
solo_folders.forEach(name => require('./' + name));
|
|
||||||
} else {
|
|
||||||
test_folders.forEach(name => require('./' + name));
|
|
||||||
}
|
|
@ -0,0 +1,59 @@
|
|||||||
|
import './ambient';
|
||||||
|
import * as assert$1 from 'assert';
|
||||||
|
export const assert = (assert$1 as unknown) as typeof assert$1 & { htmlEqual: (actual, expected, message?) => void };
|
||||||
|
import { glob } from './tiny-glob';
|
||||||
|
|
||||||
|
require('source-map-support').install();
|
||||||
|
|
||||||
|
process.env.TEST = true;
|
||||||
|
|
||||||
|
// require.extensions['.js'] = function (module, filename) {
|
||||||
|
// const exports = [];
|
||||||
|
|
||||||
|
// let code = readFileSync(filename, 'utf-8')
|
||||||
|
// .replace(/^import \* as (\w+) from ['"]([^'"]+)['"];?/gm, 'var $1 = require("$2");')
|
||||||
|
// .replace(/^import (\w+) from ['"]([^'"]+)['"];?/gm, 'var {default: $1} = require("$2");')
|
||||||
|
// .replace(/^import {([^}]+)} from ['"](.+)['"];?/gm, 'var {$1} = require("$2");')
|
||||||
|
// .replace(/^export default /gm, 'exports.default = ')
|
||||||
|
// .replace(/^export (const|let|var|class|function) (\w+)/gm, (_match, type, name) => {
|
||||||
|
// exports.push(name);
|
||||||
|
// return `${type} ${name}`;
|
||||||
|
// })
|
||||||
|
// .replace(/^export \{([^}]+)\}(?: from ['"]([^'"]+)['"];?)?/gm, (_match, names, source) => {
|
||||||
|
// names
|
||||||
|
// .split(',')
|
||||||
|
// .filter(Boolean)
|
||||||
|
// .forEach((name) => {
|
||||||
|
// exports.push(name);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return source ? `const { ${names} } = require("${source}");` : '';
|
||||||
|
// })
|
||||||
|
// .replace(/^export function (\w+)/gm, 'exports.$1 = function $1');
|
||||||
|
|
||||||
|
// exports.forEach((name) => {
|
||||||
|
// code += `\nexports.${name} = ${name};`;
|
||||||
|
// });
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// return module._compile(code, filename);
|
||||||
|
// } catch (err) {
|
||||||
|
// console.log(code);
|
||||||
|
// throw err;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
import './helpers';
|
||||||
|
import '../internal';
|
||||||
|
console.clear();
|
||||||
|
|
||||||
|
const test_folders = glob('*/index.ts', { cwd: 'test' });
|
||||||
|
const solo_folders = test_folders.filter((folder) => /\.solo/.test(folder));
|
||||||
|
|
||||||
|
if (solo_folders.length) {
|
||||||
|
if (process.env.CI) {
|
||||||
|
throw new Error('Forgot to remove `.solo` from test');
|
||||||
|
}
|
||||||
|
solo_folders.forEach((name) => require('./' + name));
|
||||||
|
} else {
|
||||||
|
test_folders.forEach((name) => require('./' + name));
|
||||||
|
}
|
@ -0,0 +1,270 @@
|
|||||||
|
import { readdirSync, lstatSync, statSync } from 'fs';
|
||||||
|
import { normalize, dirname, join, resolve, relative } from 'path';
|
||||||
|
|
||||||
|
// MIT
|
||||||
|
// tiny-glob, globrex and globalyzer by Terkel Gjervig
|
||||||
|
|
||||||
|
const CHARS = { '{': '}', '(': ')', '[': ']' };
|
||||||
|
const STRICT = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\)|(\\).|([@?!+*]\(.*\)))/;
|
||||||
|
const RELAXED = /\\(.)|(^!|[*?{}()[\]]|\(\?)/;
|
||||||
|
const isWin = process.platform === 'win32';
|
||||||
|
const SEP = isWin ? `\\\\+` : `\\/`;
|
||||||
|
const SEP_ESC = isWin ? `\\\\` : `/`;
|
||||||
|
const GLOBSTAR = `((?:[^/]*(?:/|$))*)`;
|
||||||
|
const WILDCARD = `([^/]*)`;
|
||||||
|
const GLOBSTAR_SEGMENT = `((?:[^${SEP_ESC}]*(?:${SEP_ESC}|$))*)`;
|
||||||
|
const WILDCARD_SEGMENT = `([^${SEP_ESC}]*)`;
|
||||||
|
const isHidden = /(^|[\\/])\.[^\\/.]/g;
|
||||||
|
let CACHE = {};
|
||||||
|
function isglob(str, { strict = true } = {}) {
|
||||||
|
if (str === '') return false;
|
||||||
|
let match;
|
||||||
|
const rgx = strict ? STRICT : RELAXED;
|
||||||
|
while ((match = rgx.exec(str))) {
|
||||||
|
if (match[2]) return true;
|
||||||
|
let idx = match.index + match[0].length;
|
||||||
|
const open = match[1];
|
||||||
|
const close = open ? CHARS[open] : null;
|
||||||
|
let n;
|
||||||
|
if (open && close) if ((n = str.indexOf(close, idx)) !== -1) idx = n + 1;
|
||||||
|
str = str.slice(idx);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function parent(str, { strict = false } = {}) {
|
||||||
|
str = normalize(str).replace(/\/|\\/, '/');
|
||||||
|
if (/[{[].*[/]*.*[}]]$/.test(str)) str += '/';
|
||||||
|
str += 'a';
|
||||||
|
do str = dirname(str);
|
||||||
|
while (isglob(str, { strict }) || /(^|[^\\])([{[]|\([^)]+$)/.test(str));
|
||||||
|
return str.replace(/\\([*?|[\](){}])/g, '$1');
|
||||||
|
}
|
||||||
|
function globalyzer(pattern, opts = {}) {
|
||||||
|
let base = parent(pattern, opts);
|
||||||
|
const isGlob = isglob(pattern, opts);
|
||||||
|
let glob;
|
||||||
|
if (base != '.') {
|
||||||
|
if ((glob = pattern.substr(base.length)).startsWith('/')) glob = glob.substr(1);
|
||||||
|
} else glob = pattern;
|
||||||
|
if (!isGlob) glob = (base = dirname(pattern)) !== '.' ? pattern.substr(base.length) : pattern;
|
||||||
|
if (glob.startsWith('./')) glob = glob.substr(2);
|
||||||
|
if (glob.startsWith('/')) glob = glob.substr(1);
|
||||||
|
return { base, glob, isGlob };
|
||||||
|
}
|
||||||
|
function globrex(glob, { extended = false, globstar = false, strict = false, filepath = false, flags = '' } = {}) {
|
||||||
|
let regex = '';
|
||||||
|
let segment = '';
|
||||||
|
const path = {
|
||||||
|
regex: '',
|
||||||
|
segments: [],
|
||||||
|
globstar: undefined,
|
||||||
|
};
|
||||||
|
let inGroup = false;
|
||||||
|
let inRange = false;
|
||||||
|
const ext = [];
|
||||||
|
function add(str, { split = false, last = false, only = '' } = {}) {
|
||||||
|
if (only !== 'path') regex += str;
|
||||||
|
if (filepath && only !== 'regex') {
|
||||||
|
path.regex += str === '\\/' ? SEP : str;
|
||||||
|
if (split) {
|
||||||
|
if (last) segment += str;
|
||||||
|
if (segment !== '') {
|
||||||
|
if (!flags.includes('g')) segment = `^${segment}$`; // change it 'includes'
|
||||||
|
path.segments.push(new RegExp(segment, flags));
|
||||||
|
}
|
||||||
|
segment = '';
|
||||||
|
} else {
|
||||||
|
segment += str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const escaped = (condition, str = c) => add(condition ? str : `//${c}`);
|
||||||
|
let c, n;
|
||||||
|
for (let i = 0; i < glob.length; i++) {
|
||||||
|
c = glob[i];
|
||||||
|
n = glob[i + 1];
|
||||||
|
if (['\\', '$', '^', '.', '='].includes(c)) {
|
||||||
|
add(`\\${c}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case '/': {
|
||||||
|
add(`\\${c}`, { split: true });
|
||||||
|
if (n === '/' && !strict) regex += '?';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '|':
|
||||||
|
case '(': {
|
||||||
|
escaped(ext.length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ')': {
|
||||||
|
if (ext.length) {
|
||||||
|
add(c);
|
||||||
|
const type = ext.pop();
|
||||||
|
if (type === '@') {
|
||||||
|
add('{1}');
|
||||||
|
} else if (type === '!') {
|
||||||
|
add('([^/]*)');
|
||||||
|
} else {
|
||||||
|
add(type);
|
||||||
|
}
|
||||||
|
} else add(`\\${c}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '+': {
|
||||||
|
if (n === '(' && extended) {
|
||||||
|
ext.push(c);
|
||||||
|
} else add(`\\${c}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '!': {
|
||||||
|
if (extended) {
|
||||||
|
if (inRange) {
|
||||||
|
add('^');
|
||||||
|
break;
|
||||||
|
} else if (n === '(') {
|
||||||
|
ext.push(c);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
escaped(extended && n === '(', '(?!');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '?': {
|
||||||
|
if (extended && n === '(') {
|
||||||
|
ext.push(c);
|
||||||
|
} else {
|
||||||
|
escaped(extended, '.');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '[': {
|
||||||
|
if (inRange && n === ':') {
|
||||||
|
i++; // skip [
|
||||||
|
let value = '';
|
||||||
|
while (glob[++i] !== ':') value += glob[i];
|
||||||
|
if (value === 'alnum') add('(\\w|\\d)');
|
||||||
|
else if (value === 'space') add('\\s');
|
||||||
|
else if (value === 'digit') add('\\d');
|
||||||
|
i++; // skip last ]
|
||||||
|
break;
|
||||||
|
} else if (extended) inRange = true;
|
||||||
|
escaped(extended);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ']': {
|
||||||
|
if (extended) inRange = false;
|
||||||
|
escaped(extended);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '{': {
|
||||||
|
if (extended) inGroup = true;
|
||||||
|
escaped(extended, '(');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '}': {
|
||||||
|
if (extended) inGroup = false;
|
||||||
|
escaped(extended, ')');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ',': {
|
||||||
|
escaped(inGroup, '|');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '*': {
|
||||||
|
if (n === '(' && extended) {
|
||||||
|
ext.push(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const prevChar = glob[i - 1];
|
||||||
|
let starCount = 1;
|
||||||
|
while (glob[i + 1] === '*') {
|
||||||
|
starCount++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
const nextChar = glob[i + 1];
|
||||||
|
if (!globstar) add('.*');
|
||||||
|
else {
|
||||||
|
const isGlobstar =
|
||||||
|
starCount > 1 && (prevChar === '/' || prevChar === void 0) && (nextChar === '/' || nextChar === void 0);
|
||||||
|
if (isGlobstar) {
|
||||||
|
add(GLOBSTAR, { only: 'regex' });
|
||||||
|
add(GLOBSTAR_SEGMENT, { only: 'path', last: true, split: true });
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
add(WILDCARD, { only: 'regex' });
|
||||||
|
add(WILDCARD_SEGMENT, { only: 'path' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '@': {
|
||||||
|
if (extended && n === '(') ext.push(c);
|
||||||
|
else add(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const g = flags.includes('g');
|
||||||
|
return {
|
||||||
|
regex: new RegExp(g ? regex : `^${regex}$`, flags),
|
||||||
|
path: filepath
|
||||||
|
? {
|
||||||
|
segments: [...path.segments, new RegExp(g ? segment : `^${segment}$`, flags)],
|
||||||
|
regex: new RegExp(g ? path.regex : `^${path.regex}$`, flags),
|
||||||
|
globstar: new RegExp(!g ? `^${GLOBSTAR_SEGMENT}$` : GLOBSTAR_SEGMENT, flags),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function walk(output, prefix, lexer, filesOnly, dot, cwd, dirname = '', level = 0) {
|
||||||
|
const rgx = lexer.segments[level];
|
||||||
|
const dir = join(cwd, prefix, dirname);
|
||||||
|
const files = readdirSync(dir);
|
||||||
|
let i = 0,
|
||||||
|
file;
|
||||||
|
const len = files.length;
|
||||||
|
|
||||||
|
let fullpath, relpath, stats, isMatch;
|
||||||
|
for (; i < len; i++) {
|
||||||
|
fullpath = join(dir, (file = files[i]));
|
||||||
|
relpath = dirname ? join(dirname, file) : file;
|
||||||
|
if (!dot && isHidden.test(relpath)) continue;
|
||||||
|
isMatch = lexer.regex.test(relpath);
|
||||||
|
if ((stats = CACHE[relpath]) === void 0) CACHE[relpath] = stats = lstatSync(fullpath);
|
||||||
|
if (!stats.isDirectory()) {
|
||||||
|
isMatch && output.push(relative(cwd, fullpath));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (rgx && !rgx.test(file)) continue;
|
||||||
|
if (!filesOnly && isMatch) output.push(join(prefix, relpath));
|
||||||
|
walk(output, prefix, lexer, filesOnly, dot, cwd, relpath, rgx && rgx.toString() !== lexer.globstar && ++level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function glob(str: string, { cwd = '.', absolute = false, filesOnly = false, dot = false, flush = false }) {
|
||||||
|
if (!str) return [];
|
||||||
|
const glob = globalyzer(str);
|
||||||
|
if (!glob.isGlob) {
|
||||||
|
try {
|
||||||
|
const resolved = resolve(cwd, str);
|
||||||
|
const dirent = statSync(resolved);
|
||||||
|
if (filesOnly && !dirent.isFile()) return [];
|
||||||
|
|
||||||
|
return absolute ? [resolved] : [str];
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code != 'ENOENT') throw err;
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flush) CACHE = {};
|
||||||
|
const matches = [];
|
||||||
|
const { path } = globrex(glob.glob, { filepath: true, globstar: true, extended: true });
|
||||||
|
//@ts-ignore
|
||||||
|
path.globstar = path.globstar.toString();
|
||||||
|
walk(matches, glob.base, path, filesOnly, dot, cwd, '.', 0);
|
||||||
|
return absolute ? matches.map((x) => resolve(cwd, x)) : matches;
|
||||||
|
}
|
@ -1,104 +0,0 @@
|
|||||||
import * as fs from "fs";
|
|
||||||
import * as assert from "assert";
|
|
||||||
import { svelte, loadConfig, tryToLoadJson } from "../helpers.js";
|
|
||||||
|
|
||||||
describe("validate", () => {
|
|
||||||
fs.readdirSync(`${__dirname}/samples`).forEach(dir => {
|
|
||||||
if (dir[0] === ".") return;
|
|
||||||
|
|
||||||
// add .solo to a sample directory name to only run that test
|
|
||||||
const solo = /\.solo/.test(dir);
|
|
||||||
const skip = /\.skip/.test(dir);
|
|
||||||
|
|
||||||
if (solo && process.env.CI) {
|
|
||||||
throw new Error("Forgot to remove `solo: true` from test");
|
|
||||||
}
|
|
||||||
|
|
||||||
(solo ? it.only : skip ? it.skip : it)(dir, () => {
|
|
||||||
const config = loadConfig(`${__dirname}/samples/${dir}/_config.js`);
|
|
||||||
|
|
||||||
const input = fs.readFileSync(`${__dirname}/samples/${dir}/input.svelte`, "utf-8").replace(/\s+$/, "");
|
|
||||||
const expected_warnings = tryToLoadJson(`${__dirname}/samples/${dir}/warnings.json`) || [];
|
|
||||||
const expected_errors = tryToLoadJson(`${__dirname}/samples/${dir}/errors.json`);
|
|
||||||
const options = tryToLoadJson(`${__dirname}/samples/${dir}/options.json`);
|
|
||||||
|
|
||||||
let error;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { warnings } = svelte.compile(input, {
|
|
||||||
dev: config.dev,
|
|
||||||
legacy: config.legacy,
|
|
||||||
generate: false,
|
|
||||||
customElement: config.customElement,
|
|
||||||
...options,
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.deepEqual(warnings.map(w => ({
|
|
||||||
code: w.code,
|
|
||||||
message: w.message,
|
|
||||||
pos: w.pos,
|
|
||||||
start: w.start,
|
|
||||||
end: w.end
|
|
||||||
})), expected_warnings);
|
|
||||||
} catch (e) {
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
const expected = expected_errors && expected_errors[0];
|
|
||||||
|
|
||||||
if (error || expected) {
|
|
||||||
if (error && !expected) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expected && !error) {
|
|
||||||
throw new Error(`Expected an error: ${expected.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
assert.equal(error.code, expected.code);
|
|
||||||
assert.equal(error.message, expected.message);
|
|
||||||
assert.deepEqual(error.start, expected.start);
|
|
||||||
assert.deepEqual(error.end, expected.end);
|
|
||||||
assert.equal(error.pos, expected.pos);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(error); // eslint-disable-line no-console
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("errors if options.name is illegal", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
svelte.compile("<div></div>", {
|
|
||||||
name: "not.valid",
|
|
||||||
generate: false
|
|
||||||
});
|
|
||||||
}, /options\.name must be a valid identifier/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("warns if options.name is not capitalised", () => {
|
|
||||||
const { warnings } = svelte.compile("<div></div>", {
|
|
||||||
name: "lowercase",
|
|
||||||
generate: false
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.deepEqual(warnings.map(w => ({
|
|
||||||
code: w.code,
|
|
||||||
message: w.message
|
|
||||||
})), [{
|
|
||||||
code: `options-lowercase-name`,
|
|
||||||
message: "options.name should be capitalised"
|
|
||||||
}]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not warn if options.name begins with non-alphabetic character", () => {
|
|
||||||
const { warnings } = svelte.compile("<div></div>", {
|
|
||||||
name: "_",
|
|
||||||
generate: false
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.deepEqual(warnings, []);
|
|
||||||
});
|
|
||||||
});
|
|
@ -0,0 +1,118 @@
|
|||||||
|
import * as fs from 'fs';
|
||||||
|
import { svelte, loadConfig, tryToLoadJson } from '../helpers';
|
||||||
|
import { assert } from '../test';
|
||||||
|
|
||||||
|
describe('validate', () => {
|
||||||
|
fs.readdirSync(`${__dirname}/samples`).forEach((dir) => {
|
||||||
|
if (dir[0] === '.') return;
|
||||||
|
|
||||||
|
// add .solo to a sample directory name to only run that test
|
||||||
|
const solo = /\.solo/.test(dir);
|
||||||
|
const skip = /\.skip/.test(dir);
|
||||||
|
|
||||||
|
if (solo && process.env.CI) {
|
||||||
|
throw new Error('Forgot to remove `solo: true` from test');
|
||||||
|
}
|
||||||
|
|
||||||
|
(solo ? it.only : skip ? it.skip : it)(dir, () => {
|
||||||
|
const config = loadConfig(`${__dirname}/samples/${dir}/_config.js`);
|
||||||
|
|
||||||
|
const input = fs.readFileSync(`${__dirname}/samples/${dir}/input.svelte`, 'utf-8').replace(/\s+$/, '');
|
||||||
|
const expected_warnings = tryToLoadJson(`${__dirname}/samples/${dir}/warnings.json`) || [];
|
||||||
|
const expected_errors = tryToLoadJson(`${__dirname}/samples/${dir}/errors.json`);
|
||||||
|
const options = tryToLoadJson(`${__dirname}/samples/${dir}/options.json`);
|
||||||
|
|
||||||
|
let error;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { warnings } = svelte.compile(input, {
|
||||||
|
dev: config.dev,
|
||||||
|
legacy: config.legacy,
|
||||||
|
generate: false,
|
||||||
|
customElement: config.customElement,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
warnings.map((w) => ({
|
||||||
|
code: w.code,
|
||||||
|
message: w.message,
|
||||||
|
// pos: w.pos,
|
||||||
|
// start: w.start,
|
||||||
|
// end: w.end,
|
||||||
|
})),
|
||||||
|
expected_warnings.map((w) => ({
|
||||||
|
code: w.code,
|
||||||
|
message: w.message,
|
||||||
|
// pos: w.pos,
|
||||||
|
// start: w.start,
|
||||||
|
// end: w.end,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
const expected = expected_errors && expected_errors[0];
|
||||||
|
|
||||||
|
if (error || expected) {
|
||||||
|
if (error && !expected) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expected && !error) {
|
||||||
|
throw new Error(`Expected an error: ${expected.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert.equal(error.code, expected.code);
|
||||||
|
assert.equal(error.message, expected.message);
|
||||||
|
// assert.deepEqual(error.start, expected.start);
|
||||||
|
// assert.deepEqual(error.end, expected.end);
|
||||||
|
// assert.equal(error.pos, expected.pos);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(error); // eslint-disable-line no-console
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors if options.name is illegal', () => {
|
||||||
|
assert.throws(() => {
|
||||||
|
svelte.compile('<div></div>', {
|
||||||
|
name: 'not.valid',
|
||||||
|
generate: false,
|
||||||
|
});
|
||||||
|
}, /options\.name must be a valid identifier/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('warns if options.name is not capitalised', () => {
|
||||||
|
const { warnings } = svelte.compile('<div></div>', {
|
||||||
|
name: 'lowercase',
|
||||||
|
generate: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
warnings.map((w) => ({
|
||||||
|
code: w.code,
|
||||||
|
message: w.message,
|
||||||
|
})),
|
||||||
|
[
|
||||||
|
{
|
||||||
|
code: `options-lowercase-name`,
|
||||||
|
message: 'options.name should be capitalised',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not warn if options.name begins with non-alphabetic character', () => {
|
||||||
|
const { warnings } = svelte.compile('<div></div>', {
|
||||||
|
name: '_',
|
||||||
|
generate: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(warnings, []);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in new issue