Typescript rewrite #9
|
@ -1,4 +1,2 @@
|
||||||
*.swp
|
build/
|
||||||
bin/
|
|
||||||
node_modules/
|
node_modules/
|
||||||
.DS_Store
|
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
module.exports = (grunt) ->
|
|
||||||
pkg = require './package.json'
|
|
||||||
grunt.initConfig
|
|
||||||
pkg: pkg
|
|
||||||
|
|
||||||
coffee:
|
|
||||||
compile:
|
|
||||||
options:
|
|
||||||
join: true
|
|
||||||
bare: true
|
|
||||||
files: [
|
|
||||||
'bin/ficdown.js': ['src/*.coffee']
|
|
||||||
]
|
|
||||||
|
|
||||||
stylus:
|
|
||||||
compile:
|
|
||||||
options:
|
|
||||||
compress: true
|
|
||||||
expand: true
|
|
||||||
files: [
|
|
||||||
'bin/example/player.css': ['src/example/*.styl']
|
|
||||||
]
|
|
||||||
|
|
||||||
uglify:
|
|
||||||
js:
|
|
||||||
files:
|
|
||||||
'bin/ficdown.min.js': [
|
|
||||||
'bin/ficdown.js'
|
|
||||||
]
|
|
||||||
|
|
||||||
copy:
|
|
||||||
static:
|
|
||||||
files: [
|
|
||||||
expand: true
|
|
||||||
flatten: true
|
|
||||||
src: ['src/*.html']
|
|
||||||
dest: 'bin/'
|
|
||||||
]
|
|
||||||
example:
|
|
||||||
files: [
|
|
||||||
expand: true
|
|
||||||
flatten: true
|
|
||||||
src: ['src/example/*.html', 'src/example/*.png', 'src/example/*.md', 'bin/ficdown.min.js']
|
|
||||||
dest: 'bin/example/'
|
|
||||||
]
|
|
||||||
|
|
||||||
watch:
|
|
||||||
js:
|
|
||||||
files: ['src/**/*.coffee']
|
|
||||||
tasks: ['build:js', 'copy:example']
|
|
||||||
css:
|
|
||||||
files: ['src/**/*.styl']
|
|
||||||
tasks: ['stylus:compile']
|
|
||||||
static:
|
|
||||||
files: ['src/**/*.html','src/**/*.js','src/**/*.md']
|
|
||||||
tasks: ['copy:static', 'copy:example']
|
|
||||||
|
|
||||||
for name of pkg.devDependencies when name.substring(0, 6) is 'grunt-'
|
|
||||||
grunt.loadNpmTasks name
|
|
||||||
|
|
||||||
grunt.registerTask 'build:js', [
|
|
||||||
'coffee:compile'
|
|
||||||
'uglify:js'
|
|
||||||
]
|
|
||||||
|
|
||||||
grunt.registerTask 'default', [
|
|
||||||
'coffee:compile'
|
|
||||||
'uglify:js'
|
|
||||||
'stylus:compile'
|
|
||||||
'copy:static'
|
|
||||||
'copy:example'
|
|
||||||
]
|
|
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
|
@ -2,14 +2,13 @@
|
||||||
"name": "ficdown.js",
|
"name": "ficdown.js",
|
||||||
"version": "0.9.1",
|
"version": "0.9.1",
|
||||||
"description": "A parser and player for Interactive Fiction written in Ficdown",
|
"description": "A parser and player for Interactive Fiction written in Ficdown",
|
||||||
"dependencies": {},
|
"dependencies": {
|
||||||
|
"jquery": "^3.4.0",
|
||||||
|
"markdown-it": "^8.4.2"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"coffee-script": "^1.7.1",
|
"@types/jquery": "^3.3.29",
|
||||||
"grunt": "^0.4.5",
|
"@types/markdown-it": "0.0.7",
|
||||||
"grunt-contrib-coffee": "^0.10.1",
|
"typescript": "^3.4.5"
|
||||||
"grunt-contrib-uglify": "^0.5.0",
|
|
||||||
"grunt-contrib-copy": "^0.5.0",
|
|
||||||
"grunt-contrib-watch": "^0.6.1",
|
|
||||||
"grunt-contrib-stylus": "^0.17.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export type Action = {
|
||||||
|
lineNumber: number,
|
||||||
|
state: string,
|
||||||
|
description: string,
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export type AltText = {
|
||||||
|
passed: string,
|
||||||
|
failed: string,
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
export type Anchor = {
|
||||||
|
anchor: string,
|
||||||
|
text: string,
|
||||||
|
href: string,
|
||||||
|
title: string,
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { Line } from './';
|
||||||
|
|
||||||
|
export enum BlockType {
|
||||||
|
Action,
|
||||||
|
Scene,
|
||||||
|
Story,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Block = {
|
||||||
|
lineNumber: number,
|
||||||
|
type: BlockType,
|
||||||
|
name: string,
|
||||||
|
lines: Line[],
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export type BoolHash = { [name: string]: boolean }
|
|
@ -0,0 +1,5 @@
|
||||||
|
export type Href = {
|
||||||
|
target: string,
|
||||||
|
conditions: string,
|
||||||
|
toggles: string,
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export type Line = {
|
||||||
|
lineNumber: number,
|
||||||
|
text: string,
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
export class ParseError extends Error {
|
||||||
|
constructor(message: string, public lineNumber: number) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
export type PlayerOptions = {
|
||||||
|
source: string,
|
||||||
|
id: string,
|
||||||
|
startText?: string,
|
||||||
|
endText?: string,
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { BoolHash } from './';
|
||||||
|
|
||||||
|
export type Scene = {
|
||||||
|
lineNumber: number,
|
||||||
|
name: string,
|
||||||
|
key: string,
|
||||||
|
description: string,
|
||||||
|
conditions?: BoolHash,
|
||||||
|
id?: string;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Scene, Action } from './';
|
||||||
|
|
||||||
|
export type Story = {
|
||||||
|
name: string,
|
||||||
|
description: string,
|
||||||
|
firstScene: string,
|
||||||
|
scenes: { [key: string]: Scene[] },
|
||||||
|
actions: { [key: string]: Action },
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
export * from './Action';
|
||||||
|
export * from './AltText';
|
||||||
|
export * from './Anchor';
|
||||||
|
export * from './Block';
|
||||||
|
export * from './BoolHash';
|
||||||
|
export * from './Href';
|
||||||
|
export * from './Line';
|
||||||
|
export * from './ParseError';
|
||||||
|
export * from './PlayerOptions';
|
||||||
|
export * from './Scene';
|
||||||
|
export * from './Story';
|
|
@ -0,0 +1,117 @@
|
||||||
|
import {
|
||||||
|
Action,
|
||||||
|
Block,
|
||||||
|
BlockType,
|
||||||
|
BoolHash,
|
||||||
|
Line,
|
||||||
|
ParseError,
|
||||||
|
Scene,
|
||||||
|
Story,
|
||||||
|
} from './Model';
|
||||||
|
import { Util } from './Util';
|
||||||
|
|
||||||
|
export class Parser {
|
||||||
|
public static parse(source: string): Story {
|
||||||
|
const lines = source.split(/\n|\r\n/);
|
||||||
|
const blocks = this.extractBlocks(lines);
|
||||||
|
return this.parseBlocks(blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getBlockType(hashCount: 1 | 2 | 3): BlockType {
|
||||||
|
switch(hashCount) {
|
||||||
|
case 1: return BlockType.Story;
|
||||||
|
case 2: return BlockType.Scene;
|
||||||
|
case 3: return BlockType.Action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static extractBlocks(lines: string[]): Block[] {
|
||||||
|
const blocks: Block[] = [];
|
||||||
|
let currentBlock: Block | undefined = undefined;
|
||||||
|
for(let i = 0; i < lines.length; i++) {
|
||||||
|
const match = lines[i].match(/^(#{1,3})\s+([^#].*)$/);
|
||||||
|
if(match) {
|
||||||
|
if(currentBlock) blocks.push(currentBlock);
|
||||||
|
currentBlock = {
|
||||||
|
lineNumber: i,
|
||||||
|
type: this.getBlockType(<1 | 2 | 3>match[1].length),
|
||||||
|
name: match[2],
|
||||||
|
lines: [],
|
||||||
|
};
|
||||||
|
} else if(currentBlock) {
|
||||||
|
currentBlock.lines.push({ lineNumber: i, text: lines[i] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(currentBlock) blocks.push(currentBlock);
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static parseBlocks(blocks: Block[]): Story {
|
||||||
|
let storyBlock: Block | undefined =
|
||||||
|
blocks.find(b => b.type === BlockType.Story);
|
||||||
|
|
||||||
|
if(!storyBlock) throw new ParseError('no story block', 0);
|
||||||
|
const storyName = Util.matchAnchor(storyBlock.name);
|
||||||
|
if(!storyName) throw new ParseError('no story name', storyBlock.lineNumber);
|
||||||
|
const storyHref = Util.matchHref(storyName.href);
|
||||||
|
if(!storyHref) throw new ParseError('no link to first scene', storyBlock.lineNumber);
|
||||||
|
|
||||||
|
const story: Story = {
|
||||||
|
name: storyName.text,
|
||||||
|
description: Util.trimText(storyBlock.lines.join("\n")),
|
||||||
|
firstScene: storyHref.target,
|
||||||
|
scenes: {},
|
||||||
|
actions: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
for(let block of blocks) {
|
||||||
|
switch(block.type) {
|
||||||
|
case BlockType.Scene:
|
||||||
|
const scene = this.blockToScene(block);
|
||||||
|
if(!story.scenes[scene.key]) story.scenes[scene.key] = [];
|
||||||
|
story.scenes[scene.key].push(scene);
|
||||||
|
break;
|
||||||
|
case BlockType.Action:
|
||||||
|
const action = this.blockToAction(block);
|
||||||
|
story.actions[action.state] = action;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return story;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static blockToScene(block: Block): Scene {
|
||||||
|
const sceneName = Util.matchAnchor(block.name);
|
||||||
|
let name: string | undefined = undefined;
|
||||||
|
let key: string;
|
||||||
|
let conditions: BoolHash | undefined = undefined;
|
||||||
|
if(sceneName) {
|
||||||
|
name = sceneName.title
|
||||||
|
? Util.trimText(sceneName.title)
|
||||||
|
: Util.trimText(sceneName.text);
|
||||||
|
key = Util.normalize(sceneName.text);
|
||||||
|
const href = Util.matchHref(sceneName.href);
|
||||||
|
if(href && href.conditions) conditions =
|
||||||
|
Util.toBoolHash(href.conditions.split('&'));
|
||||||
|
} else {
|
||||||
|
name = Util.trimText(block.name);
|
||||||
|
key = Util.normalize(block.name);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
key,
|
||||||
|
conditions,
|
||||||
|
description: Util.trimText(block.lines.join("\n")),
|
||||||
|
lineNumber: block.lineNumber,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static blockToAction(block: Block): Action {
|
||||||
|
return {
|
||||||
|
state: Util.normalize(block.name),
|
||||||
|
description: Util.trimText(block.lines.join("\n")),
|
||||||
|
lineNumber: block.lineNumber,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
import {
|
||||||
|
BoolHash,
|
||||||
|
PlayerOptions,
|
||||||
|
Scene,
|
||||||
|
Story,
|
||||||
|
} from './Model';
|
||||||
|
import { Parser } from './Parser';
|
||||||
|
import * as Markdown from 'markdown-it';
|
||||||
|
import * as $ from 'jquery';
|
||||||
|
|
||||||
|
export class Player {
|
||||||
|
private static converter = new Markdown();
|
||||||
|
private container: JQuery<any>;
|
||||||
|
private playerState: BoolHash = {};
|
||||||
|
private visitedScenes: BoolHash = {};
|
||||||
|
private currentScene?: Scene;
|
||||||
|
private moveCounter: number = 0;
|
||||||
|
private story: Story;
|
||||||
|
|
||||||
|
constructor(private options: PlayerOptions) {
|
||||||
|
this.story = Parser.parse(options.source);
|
||||||
|
let i = 0;
|
||||||
|
for(let [key, scenes] of Object.entries(this.story.scenes)) {
|
||||||
|
for(let scene of scenes) scene.id = `#s${ ++i }`;
|
||||||
|
}
|
||||||
|
this.container = $(`#${ options.id }`);
|
||||||
|
this.container.addClass('ficdown').data('player', this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
import { Anchor, Href, BoolHash, AltText } from './Model';
|
||||||
|
|
||||||
|
export class Util {
|
||||||
|
private static regexLib: { [name: string]: RegExp } = {
|
||||||
|
anchors: /(\[((?:[^\[\]]+|\[(?:[^\[\]]+|\[(?:[^\[\]]+|\[(?:[^\[\]]+|\[(?:[^\[\]]+|\[(?:[^\[\]]+|\[\])*\])*\])*\])*\])*\])*)\]\([ ]*((?:[^()\s]+|\((?:[^()\s]+|\((?:[^()\s]+|\((?:[^()\s]+|\((?:[^()\s]+|\((?:[^()\s]+|\(\))*\))*\))*\))*\))*\))*)[ ]*((['"])(.*?)\5[ ]*)?\))/gm,
|
||||||
|
|
||||||
|
href: /^(?:\/([a-zA-Z](?:-?[a-zA-Z0-9])*))?(?:\?((?:!?[a-zA-Z](?:-?[a-zA-Z0-9])*)(?:&!?[a-zA-Z](?:-?[a-zA-Z0-9])*)*)?)?(?:#((?:[a-zA-Z](?:-?[a-zA-Z0-9])*)(?:\+[a-zA-Z](?:-?[a-zA-Z0-9])*)*))?$/,
|
||||||
|
|
||||||
|
trim: /^\s+|\s+$/g,
|
||||||
|
|
||||||
|
altText: /^((?:[^|\\]|\\.)*)(?:\|((?:[^|\\]|\\.)+))?$/,
|
||||||
|
|
||||||
|
escapeChar: /\\(?=[^\\])/g,
|
||||||
|
|
||||||
|
emptyListItem: /^[ ]*-\s*([\r\n]+|$)/gm,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static matchToAnchor(match: RegExpExecArray): Anchor {
|
||||||
|
const result: Anchor = {
|
||||||
|
anchor: match[1],
|
||||||
|
text: match[2],
|
||||||
|
href: match[3],
|
||||||
|
title: match[6],
|
||||||
|
};
|
||||||
|
if(result.href.indexOf('"') === 0) {
|
||||||
|
result.title = result.href.substring(1, result.href.length - 1);
|
||||||
|
result.href = '';
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static matchAnchor(text: string): Anchor | undefined {
|
||||||
|
const match = this.regexLib.anchors.exec(text);
|
||||||
|
if(match) return this.matchToAnchor(match);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static matchAnchors(text: string): Anchor[] {
|
||||||
|
let match: RegExpExecArray | null;
|
||||||
|
const anchors: Anchor[] = [];
|
||||||
|
while(match = this.regexLib.anchors.exec(text)) {
|
||||||
|
anchors.push(this.matchToAnchor(match));
|
||||||
|
}
|
||||||
|
return anchors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static matchHref(text: string): Href | undefined {
|
||||||
|
const match = this.regexLib.href.exec(text);
|
||||||
|
if(match) {
|
||||||
|
return {
|
||||||
|
target: match[1],
|
||||||
|
conditions: match[2],
|
||||||
|
toggles: match[3],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static trimText(text: string): string {
|
||||||
|
return text.replace(this.regexLib.trim, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static normalize(text: string): string {
|
||||||
|
return text.toLowerCase().replace(/^\W+|\W+$/g, '').replace(/\W+/g, '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static toBoolHash(names: string[]): BoolHash | undefined {
|
||||||
|
if(names) {
|
||||||
|
const hash: BoolHash = {};
|
||||||
|
for(let name of names) {
|
||||||
|
if(name.indexOf('!') === 0) {
|
||||||
|
hash[name.substring(1, name.length)] = false;
|
||||||
|
} else {
|
||||||
|
hash[name] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static conditionsMet(state: BoolHash, conditions: BoolHash): boolean {
|
||||||
|
for(let [cond, val] of Object.entries(conditions)) {
|
||||||
|
if((val && !state[cond]) || (!val && state[cond])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static splitAltText(text: string): AltText | undefined {
|
||||||
|
const match = this.regexLib.altText.exec(text);
|
||||||
|
if(match) {
|
||||||
|
return {
|
||||||
|
passed: match[0],
|
||||||
|
failed: match[1],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,76 +0,0 @@
|
||||||
parseText = (text) ->
|
|
||||||
lines = text.split /\n|\r\n/
|
|
||||||
blocks = extractBlocks lines
|
|
||||||
story = parseBlocks blocks
|
|
||||||
|
|
||||||
getBlockType = (hashCount) ->
|
|
||||||
switch hashCount
|
|
||||||
when 1 then 'story'
|
|
||||||
when 2 then 'scene'
|
|
||||||
when 3 then 'action'
|
|
||||||
|
|
||||||
extractBlocks = (lines) ->
|
|
||||||
blocks = []
|
|
||||||
currentBlock = null
|
|
||||||
for line in lines
|
|
||||||
match = line.match /^(#{1,3})\s+([^#].*)$/
|
|
||||||
if match?
|
|
||||||
if currentBlock != null
|
|
||||||
blocks.push currentBlock
|
|
||||||
currentBlock =
|
|
||||||
type: getBlockType match[1].length
|
|
||||||
name: match[2]
|
|
||||||
lines: []
|
|
||||||
else
|
|
||||||
currentBlock.lines.push line
|
|
||||||
if currentBlock != null
|
|
||||||
blocks.push currentBlock
|
|
||||||
return blocks
|
|
||||||
|
|
||||||
parseBlocks = (blocks) ->
|
|
||||||
storyBlock = null
|
|
||||||
for block in blocks
|
|
||||||
if block.type == 'story'
|
|
||||||
storyBlock = block
|
|
||||||
break
|
|
||||||
storyName = matchAnchor storyBlock.name
|
|
||||||
storyHref = matchHref storyName.href
|
|
||||||
story =
|
|
||||||
name: storyName.text
|
|
||||||
description: trimText storyBlock.lines.join "\n"
|
|
||||||
firstScene: storyHref.target
|
|
||||||
scenes: {}
|
|
||||||
actions: {}
|
|
||||||
for block in blocks
|
|
||||||
switch block.type
|
|
||||||
when 'scene'
|
|
||||||
scene = blockToScene block
|
|
||||||
if !story.scenes[scene.key]
|
|
||||||
story.scenes[scene.key] = []
|
|
||||||
story.scenes[scene.key].push scene
|
|
||||||
when 'action'
|
|
||||||
action = blockToAction block
|
|
||||||
story.actions[action.state] = action
|
|
||||||
return story
|
|
||||||
|
|
||||||
blockToScene = (block) ->
|
|
||||||
sceneName = matchAnchor block.name
|
|
||||||
if sceneName?
|
|
||||||
title = if sceneName.title? then trimText sceneName.title else trimText sceneName.text
|
|
||||||
key = normalize sceneName.text
|
|
||||||
href = matchHref sceneName.href
|
|
||||||
if href?.conditions?
|
|
||||||
conditions = toBoolHash href.conditions.split '&'
|
|
||||||
else
|
|
||||||
title = trimText block.name
|
|
||||||
key = normalize block.name
|
|
||||||
scene =
|
|
||||||
name: if title != '' then title else null
|
|
||||||
key: key
|
|
||||||
description: trimText block.lines.join "\n"
|
|
||||||
conditions: if conditions? then conditions else null
|
|
||||||
|
|
||||||
blockToAction = (block) ->
|
|
||||||
action =
|
|
||||||
state: normalize block.name
|
|
||||||
description: trimText block.lines.join "\n"
|
|
|
@ -1,89 +0,0 @@
|
||||||
regexLib =
|
|
||||||
|
|
||||||
anchors: /(\[((?:[^\[\]]+|\[(?:[^\[\]]+|\[(?:[^\[\]]+|\[(?:[^\[\]]+|\[(?:[^\[\]]+|\[(?:[^\[\]]+|\[\])*\])*\])*\])*\])*\])*)\]\([ ]*((?:[^()\s]+|\((?:[^()\s]+|\((?:[^()\s]+|\((?:[^()\s]+|\((?:[^()\s]+|\((?:[^()\s]+|\(\))*\))*\))*\))*\))*\))*)[ ]*((['"])(.*?)\5[ ]*)?\))/gm
|
|
||||||
|
|
||||||
href: /^(?:\/([a-zA-Z](?:-?[a-zA-Z0-9])*))?(?:\?((?:!?[a-zA-Z](?:-?[a-zA-Z0-9])*)(?:&!?[a-zA-Z](?:-?[a-zA-Z0-9])*)*)?)?(?:#((?:[a-zA-Z](?:-?[a-zA-Z0-9])*)(?:\+[a-zA-Z](?:-?[a-zA-Z0-9])*)*))?$/
|
|
||||||
|
|
||||||
trim: /^\s+|\s+$/g
|
|
||||||
|
|
||||||
altText: /^((?:[^|\\]|\\.)*)(?:\|((?:[^|\\]|\\.)+))?$/
|
|
||||||
|
|
||||||
escapeChar: /\\(?=[^\\])/g
|
|
||||||
|
|
||||||
emptyListItem: /^[ ]*-\s*([\r\n]+|$)/gm
|
|
||||||
|
|
||||||
matchAnchor = (text) ->
|
|
||||||
re = new RegExp regexLib.anchors
|
|
||||||
match = re.exec text
|
|
||||||
if match?
|
|
||||||
result =
|
|
||||||
anchor: match[1]
|
|
||||||
text: match[2]
|
|
||||||
href: match[3]
|
|
||||||
title: match[6]
|
|
||||||
if result.href.indexOf('"') == 0
|
|
||||||
result.title = result.href.substring 1, result.href.length - 1
|
|
||||||
result.href = ''
|
|
||||||
return result
|
|
||||||
return match
|
|
||||||
|
|
||||||
matchAnchors = (text) ->
|
|
||||||
re = new RegExp regexLib.anchors
|
|
||||||
anchors = []
|
|
||||||
while match = re.exec text
|
|
||||||
anchor =
|
|
||||||
anchor: match[1]
|
|
||||||
text: match[2]
|
|
||||||
href: match[3]
|
|
||||||
title: match[6]
|
|
||||||
if anchor.href.indexOf('"') == 0
|
|
||||||
anchor.title = anchor.href.substring 1, anchor.href.length - 1
|
|
||||||
anchor.href = ''
|
|
||||||
anchors.push anchor
|
|
||||||
return anchors
|
|
||||||
|
|
||||||
trimText = (text) ->
|
|
||||||
text.replace regexLib.trim, ''
|
|
||||||
|
|
||||||
matchHref = (href) ->
|
|
||||||
re = new RegExp regexLib.href
|
|
||||||
match = re.exec href
|
|
||||||
if match?
|
|
||||||
result =
|
|
||||||
target: match[1]
|
|
||||||
conditions: match[2]
|
|
||||||
toggles: match[3]
|
|
||||||
return result
|
|
||||||
return match
|
|
||||||
|
|
||||||
normalize = (text) ->
|
|
||||||
text.toLowerCase().replace(/^\W+|\W+$/g, '').replace /\W+/g, '-'
|
|
||||||
|
|
||||||
toBoolHash = (names) ->
|
|
||||||
if !names?
|
|
||||||
return null
|
|
||||||
hash = {}
|
|
||||||
for name in names
|
|
||||||
if name.indexOf('!') == 0
|
|
||||||
hash[name.substring 1, name.length] = false
|
|
||||||
else
|
|
||||||
hash[name] = true
|
|
||||||
return hash
|
|
||||||
|
|
||||||
conditionsMet = (state, conditions) ->
|
|
||||||
met = true
|
|
||||||
for cond, val of conditions
|
|
||||||
if (val and !state[cond]) or (!val and state[cond])
|
|
||||||
met = false
|
|
||||||
break
|
|
||||||
return met
|
|
||||||
|
|
||||||
splitAltText = (text) ->
|
|
||||||
re = new RegExp regexLib.altText
|
|
||||||
match = re.exec text
|
|
||||||
if match?
|
|
||||||
result =
|
|
||||||
passed: match[1]
|
|
||||||
failed: match[2]
|
|
||||||
return result
|
|
||||||
return
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": [ "es2017" ],
|
||||||
|
"target": "es6",
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"outDir": "./build",
|
||||||
|
"declaration": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"strict": true,
|
||||||
|
"sourceMap": true
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue